当前位置: 首页 > news >正文

贵港网站建设2023新冠结束了吗

贵港网站建设,2023新冠结束了吗,手工做刀网站,最新网游上一篇内容说到InitAppsHelper这个类的initSystemApps函数,只说了一下几个重要参数的来源还没展开,这里继续,有兴趣的可以看链接: Android 启动时应用的安装解析过程《一》 一、系统应用的扫描安装 /*** Install apps from system dirs.*/Gu…

上一篇内容说到InitAppsHelper这个类的initSystemApps函数,只说了一下几个重要参数的来源还没展开,这里继续,有兴趣的可以看链接: Android 启动时应用的安装解析过程《一》

一、系统应用的扫描安装

	/*** Install apps from system dirs.*/@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})public OverlayConfig initSystemApps(PackageParser2 packageParser,WatchedArrayMap<String, PackageSetting> packageSettings,int[] userIds, long startTime) {// Prepare apex package info before scanning APKs, this information is needed when// scanning apk in apex.// 扫描系统中apex信息,为扫描APK做准备,apex是系统中一种新的模块化组件final List<ApexManager.ScanResult> apexScanResults = scanApexPackagesTraced(packageParser);mApexManager.notifyScanResult(apexScanResults);// 扫描系统目录中的apkscanSystemDirs(packageParser, mExecutorService);// Parse overlay configuration files to set default enable state, mutability, and// priority of system overlays.final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {final String apexPackageName = mApexManager.getActivePackageNameForApexModuleName(apexInfo.apexModuleName);for (String packageName : mApexManager.getApksInApex(apexPackageName)) {apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);}}// 解析系统目录的overlay并把它使能final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(consumer -> mPm.forEachPackageState(mPm.snapshotComputer(),packageState -> {var pkg = packageState.getPkg();if (pkg != null) {consumer.accept(pkg, packageState.isSystem(),apkInApexPreInstalledPaths.get(pkg.getPackageName()));}}));// do this first before mucking with mPackages for the "expecting better" case// 做一些优化,比如禁用一些需要禁用的apk,删除掉已经被删除的应用缓存updateStubSystemAppsList(mStubSystemApps);mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);logSystemAppsScanningTime(startTime);return overlayConfig;}

1.扫描系统目录

private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {File frameworkDir = new File(Environment.getRootDirectory(), "framework");// Collect vendor/product/system_ext overlay packages. (Do this before scanning// any apps.)// For security and version matching reason, only consider overlay packages if they// reside in the right directory.for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {final ScanPartition partition = mDirsToScanAsSystem.get(i);if (partition.getOverlayFolder() == null) {continue;}// 扫描系统分区的overlay 文件夹scanDirTracedLI(partition.getOverlayFolder(),mSystemParseFlags, mSystemScanFlags | partition.scanFlag,packageParser, executorService, partition.apexInfo);}// 扫描system/framework文件夹scanDirTracedLI(frameworkDir,mSystemParseFlags, mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,packageParser, executorService, null);if (!mPm.mPackages.containsKey("android")) {throw new IllegalStateException("Failed to load frameworks package; check log for warnings");}for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {final ScanPartition partition = mDirsToScanAsSystem.get(i);if (partition.getPrivAppFolder() != null) {// 扫描系统分区的priv-app文件夹scanDirTracedLI(partition.getPrivAppFolder(),mSystemParseFlags,mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,packageParser, executorService, partition.apexInfo);}// 扫描系统分区的app文件夹scanDirTracedLI(partition.getAppFolder(),mSystemParseFlags, mSystemScanFlags | partition.scanFlag,packageParser, executorService, partition.apexInfo);}}

上面可以看到,这个函数里面将系统分区的overlay,app,还有jar包都扫描了个遍,然后我们看下到底这个scanDirTracedLI函数里面做了哪些事情

private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,PackageParser2 packageParser, ExecutorService executorService,@Nullable ApexManager.ActiveApexInfo apexInfo) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");try {if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {// when scanning apk in apexes, we want to check the maxSdkVersionparseFlags |= PARSE_APK_IN_APEX;}// 调用到了InstallPackageHelper的installPackagesFromDirmInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags,scanFlags, packageParser, executorService, apexInfo);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}
}
InstallPackageHelper
public void installPackagesFromDir(File scanDir, int parseFlags,int scanFlags, PackageParser2 packageParser, ExecutorService executorService,@Nullable ApexManager.ActiveApexInfo apexInfo) {//首先将所有的文件列出来final File[] files = scanDir.listFiles();if (ArrayUtils.isEmpty(files)) {Log.d(TAG, "No files in app dir " + scanDir);return;}if (DEBUG_PACKAGE_SCANNING) {Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags+ " flags=0x" + Integer.toHexString(parseFlags));}// 这个又是个专门解析包的类ParallelPackageParser parallelPackageParser =new ParallelPackageParser(packageParser, executorService);// Submit files for parsing in parallelint fileCount = 0;for (File file : files) {// 这里判断是不是包:是apk文件或者是文件夹并且不是stageName,这个stageName是指// vmdl*.tmp,smdl*.tmp,smdl2tmp这些类的文件final boolean isPackage = (isApkFile(file) || file.isDirectory())&& !PackageInstallerService.isStageName(file.getName());if (!isPackage) {// Ignore entries which are not packagescontinue;}// 这里如果携带了SCAN_DROP_CACHE的flag会清除缓存if ((scanFlags & SCAN_DROP_CACHE) != 0) {final PackageCacher cacher = new PackageCacher(mPm.getCacheDir(),mPm.mPackageParserCallback);Log.w(TAG, "Dropping cache of " + file.getAbsolutePath());cacher.cleanCachedResult(file);}// 这里提交给解析器解析parallelPackageParser.submit(file, parseFlags);fileCount++;}// Process results one by onefor (; fileCount > 0; fileCount--) {ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();Throwable throwable = parseResult.throwable;int errorCode = PackageManager.INSTALL_SUCCEEDED;String errorMsg = null;// 如果没有异常就表示解析成功另外两个条件属于失败了if (throwable == null) {try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "addForInitLI");// 这里初始化addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,new UserHandle(UserHandle.USER_SYSTEM), apexInfo);} catch (PackageManagerException e) {errorCode = e.error;errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();Slog.w(TAG, errorMsg);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}} else if (throwable instanceof PackageManagerException) {PackageManagerException e = (PackageManagerException) throwable;errorCode = e.error;errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();Slog.w(TAG, errorMsg);} else {throw new IllegalStateException("Unexpected exception occurred while parsing "+ parseResult.scanFile, throwable);}// apex的安装单独报给ApexManagerif ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);}// Delete invalid userdata apps// 没安装成功的会在这里清除if ((scanFlags & SCAN_AS_SYSTEM) == 0&& errorCode != PackageManager.INSTALL_SUCCEEDED) {logCriticalInfo(Log.WARN,"Deleting invalid package at " + parseResult.scanFile);mRemovePackageHelper.removeCodePath(parseResult.scanFile);}}
}

从上面可以看出主要就做了两件事情,把文件夹下面的包一一解析,并做初始化,看看如何解析的先:
ParallelPackageParser submit之后

2.开始解析

/*---------------------------ParallelPackageParser start ---------------------------*/
public void submit(File scanFile, int parseFlags) {// 直接开线程开始解析mExecutorService.submit(() -> {ParseResult pr = new ParseResult();Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");try {pr.scanFile = scanFile;// 解析pr.parsedPackage = parsePackage(scanFile, parseFlags);} catch (Throwable e) {pr.throwable = e;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}try {mQueue.put(pr);} catch (InterruptedException e) {Thread.currentThread().interrupt();// Propagate result to callers of take().// This is helpful to prevent main thread from getting stuck waiting on// ParallelPackageParser to finish in case of interruptionmInterruptedInThread = Thread.currentThread().getName();}});
}protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageManagerException {try {// 发现这里又交给PackageParser2去做了return mPackageParser.parsePackage(scanFile, parseFlags, true);} catch (PackageParserException e) {throw new PackageManagerException(e.error, e.getMessage(), e);}
}
/*---------------------------ParallelPackageParser end---------------------------*/
/*---------------------------PackageParser2 start---------------------------*/
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {// 列出所有的文件var files = packageFile.listFiles();// Apk directory is directly nested under the current directoryif (ArrayUtils.size(files) == 1 && files[0].isDirectory()) {packageFile = files[0];}if (useCaches && mCacher != null) {// 这里会去检查有没有缓存,缓存是存在data/system/目录下如果有缓存则不再解析ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);if (parsed != null) {return parsed;}}long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;ParseInput input = mSharedResult.get().reset();// 这里又交给了ParsingPackageUtils这个类去干活了ParseResult<ParsingPackage> result = mParsingUtils.parsePackage(input, packageFile, flags);if (result.isError()) {throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),result.getException());}ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;// 这里解析好的结果保存到缓存,也就是只要APK被解析过一次就会存在缓存了if (mCacher != null) {mCacher.cacheResult(packageFile, flags, parsed);}if (LOG_PARSE_TIMINGS) {parseTime = cacheTime - parseTime;cacheTime = SystemClock.uptimeMillis() - cacheTime;if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime+ "ms, update_cache=" + cacheTime + " ms");}}return parsed;
}/*---------------------------PackageParser2 end---------------------------*/
/*---------------------------ParsingPackageUtils start---------------------------*/
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {// 如果是文件夹则走if 文件则走else,这里为什么会这样分,那/system/app目录来说,// 系统在预置APP的时候可能是先在该目录下新建一层目录再放APK,也有可能直接放置一个APK在该目录下if (packageFile.isDirectory()) {return parseClusterPackage(input, packageFile,  flags);} else {return parseMonolithicPackage(input, packageFile, flags);}
}// 先看下解析目录parseClusterPackage
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,int flags) {int liteParseFlags = 0;// 这里判断是不是在解析APEX的时候解析APKif ((flags & PARSE_APK_IN_APEX) != 0) {liteParseFlags |= PARSE_APK_IN_APEX;}// 轻量解析APK,这里会解析APK的签名信息,AndroidManifest.xml中除了Activity,Service,ContentProvider及权限以外的信息,// 顺便会做一些校验比如SDK版本,签名校验,系统目录的APK 可以跳过签名校验(签名校验从v4到v1逐一校验),这一部分设计是为了节省时间final ParseResult<PackageLite> liteResult =ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags);// 没有错误说明各种校验通过了if (liteResult.isError()) {return input.error(liteResult);}final PackageLite lite = liteResult.getResult();// Build the split dependency tree.SparseArray<int[]> splitDependencies = null;final SplitAssetLoader assetLoader;// 如果是APKS 格式的这里会创建资源依赖树if (lite.isIsolatedSplits() && !ArrayUtils.isEmpty(lite.getSplitNames())) {try {splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);} catch (SplitAssetDependencyLoader.IllegalDependencyException e) {return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());}} else {assetLoader = new DefaultSplitAssetLoader(lite, flags);}try {final File baseApk = new File(lite.getBaseApkPath());boolean shouldSkipComponents = lite.isIsSdkLibrary() && disallowSdkLibsToBeApps();// 这里解析APKfinal ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,lite.getPath(), assetLoader, flags, shouldSkipComponents);if (result.isError()) {return input.error(result);}ParsingPackage pkg = result.getResult();// 如果是APKS格式进行另外的解析if (!ArrayUtils.isEmpty(lite.getSplitNames())) {pkg.asSplit(lite.getSplitNames(),lite.getSplitApkPaths(),lite.getSplitRevisionCodes(),splitDependencies);final int num = lite.getSplitNames().length;for (int i = 0; i < num; i++) {final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);final ParseResult<ParsingPackage> split =parseSplitApk(input, pkg, i, splitAssets, flags);if (split.isError()) {return input.error(split);}}}pkg.set32BitAbiPreferred(lite.isUse32bitAbi());return input.success(pkg);} catch (IllegalArgumentException e) {return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK: INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e);} finally {IoUtils.closeQuietly(assetLoader);}
}
/*******parseBaseApk******/private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,String codePath, SplitAssetLoader assetLoader, int flags,boolean shouldSkipComponents) {......// 又开始解析AndroidManifest.xmltry (XmlResourceParser parser = assets.openXmlResourceParser(cookie,ANDROID_MANIFEST_FILENAME)) {final Resources res = new Resources(assets, mDisplayMetrics, null);// 这里又一个重载解析APKParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,parser, flags, shouldSkipComponents);if (result.isError()) {return input.error(result.getErrorCode(),apkPath + " (at " + parser.getPositionDescription() + "): "+ result.getErrorMessage());}final ParsingPackage pkg = result.getResult();if (assets.containsAllocatedTable()) {final ParseResult<?> deferResult = input.deferError("Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"+ " the resources.arsc of installed APKs to be stored uncompressed"+ " and aligned on a 4-byte boundary",DeferredError.RESOURCES_ARSC_COMPRESSED);if (deferResult.isError()) {return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,deferResult.getErrorMessage());}}ApkAssets apkAssets = assetLoader.getBaseApkAssets();boolean definesOverlayable = false;try {// 查询该应用是否支持overlay,一般定义了相应的overlayabledefinesOverlayable = apkAssets.definesOverlayable();} catch (IOException ignored) {// Will fail if there's no packages in the ApkAssets, which can be treated as false}// 如果可以这里会查找到可以被overlay的域if (definesOverlayable) {SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();int size = packageNames.size();for (int index = 0; index < size; index++) {String packageName = packageNames.valueAt(index);Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);if (overlayableToActor != null && !overlayableToActor.isEmpty()) {for (String overlayable : overlayableToActor.keySet()) {pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));}}}}pkg.setVolumeUuid(volumeUuid);// 这里又是查询验证签名信息if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {final ParseResult<SigningDetails> ret =getSigningDetails(input, pkg, false /*skipVerify*/);if (ret.isError()) {return input.error(ret);}pkg.setSigningDetails(ret.getResult());} else {pkg.setSigningDetails(SigningDetails.UNKNOWN);}if (Flags.aslInApkAppMetadataSource()) {try (InputStream in = assets.open(APP_METADATA_FILE_NAME)) {pkg.setAppMetadataFileInApk(true);} catch (Exception e) { }}return input.success(pkg);} catch (Exception e) {return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,"Failed to read manifest from " + apkPath, e);}}/*******parseBaseApk 重载******/
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,String codePath, Resources res, XmlResourceParser parser, int flags,boolean shouldSkipComponents)throws XmlPullParserException, IOException {final String splitName;final String pkgName;// 轻量解析,包名信息之类的ParseResult<Pair<String, String>> packageSplitResult =ApkLiteParseUtils.parsePackageSplitNames(input, parser);if (packageSplitResult.isError()) {return input.error(packageSplitResult);}Pair<String, String> packageSplit = packageSplitResult.getResult();pkgName = packageSplit.first;splitName = packageSplit.second;if (!TextUtils.isEmpty(splitName)) {return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,"Expected base APK, but found split " + splitName);}final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);try {// 是否是core app ,类似系统设置final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/,"coreApp", false);final ParsingPackage pkg = mCallback.startParsingPackage(pkgName, apkPath, codePath, manifestArray, isCoreApp);// 解析AndroidManinfest里面的各个TAG,真正解析的开始final ParseResult<ParsingPackage> result =parseBaseApkTags(input, pkg, manifestArray, res, parser, flags,shouldSkipComponents);if (result.isError()) {return result;}return input.success(pkg);} finally {manifestArray.recycle();}}/**** parseBaseApkTags ****/
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,TypedArray sa, Resources res, XmlResourceParser parser, int flags,boolean shouldSkipComponents) throws XmlPullParserException, IOException {// 解析共享uidParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);if (sharedUserResult.isError()) {return sharedUserResult;}// 用于标记系统为可更新,通常和动态系统分区及增量更新机制有关。final boolean updatableSystem = parser.getAttributeBooleanValue(null /*namespace*/,"updatableSystem", true);// 用于设备恢复模式下的紧急安装或恢复。final String emergencyInstaller = parser.getAttributeValue(null /*namespace*/,"emergencyInstaller");pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,R.styleable.AndroidManifest_installLocation, sa)).setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,R.styleable.AndroidManifest_targetSandboxVersion, sa))/* Set the global "on SD card" flag */.setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0).setUpdatableSystem(updatableSystem).setEmergencyInstaller(emergencyInstaller);boolean foundApp = false;final int depth = parser.getDepth();int type;while ((type = parser.next()) != XmlPullParser.END_DOCUMENT&& (type != XmlPullParser.END_TAG|| parser.getDepth() > depth)) {if (type != XmlPullParser.START_TAG) {continue;}if (sAconfigFlags.skipCurrentElement(parser)) {continue;}String tagName = parser.getName();final ParseResult result;// <application> has special logic, so it's handled outside the general method// 解析Application TAG配置及四大组件信息if (TAG_APPLICATION.equals(tagName)) {if (foundApp) {if (RIGID_PARSER) {result = input.error("<manifest> has more than one <application>");} else {Slog.w(TAG, "<manifest> has more than one <application>");result = input.success(null);}} else {foundApp = true;result = parseBaseApplication(input, pkg, res, parser, flags,shouldSkipComponents);}} else {// Application 以外的TAG信息result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);}if (result.isError()) {return input.error(result);}}if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {ParseResult<?> deferResult = input.deferError("<manifest> does not contain an <application> or <instrumentation>",DeferredError.MISSING_APP_TAG);if (deferResult.isError()) {return input.error(deferResult);}}return validateBaseApkTags(input, pkg, flags);}

后面都是一些解析细节了,不在追述,值得注意的是大部分APK 只会解析一次会将APK 的信息存储在/data/system/package_caches,下面除非apk出现了更新否则不会再重新解析


文章转载自:
http://tortoise.qpqb.cn
http://polysepalous.qpqb.cn
http://endothelioma.qpqb.cn
http://camboose.qpqb.cn
http://tpn.qpqb.cn
http://tohubohu.qpqb.cn
http://he.qpqb.cn
http://lambeth.qpqb.cn
http://comradely.qpqb.cn
http://suntanned.qpqb.cn
http://jyland.qpqb.cn
http://willemstad.qpqb.cn
http://chance.qpqb.cn
http://unschooled.qpqb.cn
http://cropless.qpqb.cn
http://numberless.qpqb.cn
http://upbow.qpqb.cn
http://identity.qpqb.cn
http://euclidean.qpqb.cn
http://pelisse.qpqb.cn
http://macroscopic.qpqb.cn
http://sandiver.qpqb.cn
http://lycee.qpqb.cn
http://lumpenprole.qpqb.cn
http://zymosan.qpqb.cn
http://analysissitus.qpqb.cn
http://isogamy.qpqb.cn
http://ephemerous.qpqb.cn
http://kremlin.qpqb.cn
http://seccotine.qpqb.cn
http://thrombogen.qpqb.cn
http://pandoor.qpqb.cn
http://proverbialist.qpqb.cn
http://aficionado.qpqb.cn
http://pentastich.qpqb.cn
http://quiescence.qpqb.cn
http://healing.qpqb.cn
http://dunhuang.qpqb.cn
http://immunocompetence.qpqb.cn
http://herodian.qpqb.cn
http://koodoo.qpqb.cn
http://deglutinate.qpqb.cn
http://firehorse.qpqb.cn
http://utopism.qpqb.cn
http://chirk.qpqb.cn
http://endorse.qpqb.cn
http://cerous.qpqb.cn
http://unco.qpqb.cn
http://hagdon.qpqb.cn
http://punctuative.qpqb.cn
http://dindle.qpqb.cn
http://koa.qpqb.cn
http://cybernetical.qpqb.cn
http://chloracne.qpqb.cn
http://southeast.qpqb.cn
http://dogfight.qpqb.cn
http://fsf.qpqb.cn
http://schmuck.qpqb.cn
http://plasmolyse.qpqb.cn
http://cupula.qpqb.cn
http://lyons.qpqb.cn
http://sequence.qpqb.cn
http://idolize.qpqb.cn
http://bob.qpqb.cn
http://bowdlerism.qpqb.cn
http://auriculate.qpqb.cn
http://sulfanilamide.qpqb.cn
http://papilloedema.qpqb.cn
http://extracurriculum.qpqb.cn
http://astigmatoscopy.qpqb.cn
http://tourism.qpqb.cn
http://algebraical.qpqb.cn
http://kama.qpqb.cn
http://court.qpqb.cn
http://nitrotrichloromethane.qpqb.cn
http://varia.qpqb.cn
http://albuminuria.qpqb.cn
http://logjam.qpqb.cn
http://scholarch.qpqb.cn
http://subacid.qpqb.cn
http://pomp.qpqb.cn
http://feedforward.qpqb.cn
http://sandakan.qpqb.cn
http://automatic.qpqb.cn
http://dqdb.qpqb.cn
http://scalloping.qpqb.cn
http://euryphagous.qpqb.cn
http://resectoscope.qpqb.cn
http://causal.qpqb.cn
http://immortalisation.qpqb.cn
http://waive.qpqb.cn
http://humane.qpqb.cn
http://pookoo.qpqb.cn
http://comparably.qpqb.cn
http://sporogonium.qpqb.cn
http://cardiocirculatory.qpqb.cn
http://bimolecular.qpqb.cn
http://sungkiang.qpqb.cn
http://cradlesong.qpqb.cn
http://matriculant.qpqb.cn
http://www.dt0577.cn/news/90117.html

相关文章:

  • 做网站的报价方案百度指数 移民
  • 网站建设方维网络营销环境分析
  • 八年级信息上册如何做网站湖南百度推广开户
  • 国内ui做的好的网站有哪些泉州seo网站排名
  • java做网站系统需要学什么公司做网络推广怎么做
  • 地图素材如何做ppt模板下载网站百度seo新算法
  • 网站建设带后台带微商城永久不收费免费的聊天软件
  • 做外国网站买域名google浏览器下载安装
  • 网站建设推广ppt网络营销推广策划步骤
  • 制作网站网站教你免费申请个人网站
  • .net网站开发后编译百度app浏览器下载
  • 领域网站建设中国制造网外贸平台
  • 俄语在线网站建设网站排名快速提升工具
  • 找马云做网站学生班级优化大师
  • 做响应式网站设计做图怎么搞一份完整的营销策划方案
  • 无锡网站建设咨询热线长沙网站推广和优化
  • 网站建设完成确认书镇江网站制作公司
  • 个人做商机网站如何盈利百度广告推广怎么收费
  • 网站图片移动怎么做免费发布广告信息平台
  • 汕头有什么招聘平台seo关键词外包
  • 网站推广连接怎么做的站长平台
  • 网站的优化策略网址提交百度收录
  • 公司网站模板建设查询网站注册信息
  • 单页网站制作教程福州seo关键字推广
  • 网站定制文章列表项怎么做百度搜索风云榜电视剧
  • 做网站的哪里便宜南宁网络推广培训机构
  • 能不能自己做网站推广国际时事新闻最新消息
  • 做网站页面遇到的问题商业公司的域名
  • 福州制作网站企业找客户的软件有哪些
  • 网站建设3要素百度快速优化软件