日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android中应用安装分析

發布時間:2024/10/12 Android 78 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android中应用安装分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

#1 安裝方式

  • 1 安裝系統APK和預制APK時,通過PMS的構造函數中安裝,即第一次開機時安裝應用,沒有安裝界面。
  • 2 網絡下載安裝,通過應用商店等,即調用PackageManager.installPackages(),有安裝界面。
  • 3 通過adb工具安裝,沒有安裝界面,它通過啟動pm腳本的形式,然后調用com.android.commands.pm.Pm類,之后調用到PMS.installStage()完成安裝。
  • 4 安裝本地apk,有安裝界面,由PackageInstaller系統應用安裝。
    上述幾種方式均通過PackageInstallObserver來監聽安裝是否成功。

#2 安裝流程分析

2.1 首次安裝

首次安裝即系統第一次開機時安裝應用,包括系統應用和預制應用,其最主要過程在PMS構造函數中,

整個過程關鍵步驟大致為上述15步,與應用安裝相關實際上就是掃描和安裝兩步。方法調用時序圖如圖1所示。
[圖1 PMS安裝應用時序圖]

  • 1 向動態設置中添加系統默認的共享ID(system、phone、log、nfc、bluetooth、shell、se等)。
  • 2 初始化成員變量,如Installer、PackageDexOptimizer、DexManager、ArtManagerService、MoveCallbacks、OnPermissionChangeListeners等,并獲取系統配置。
  • 3 啟動一個服務類線程。
  • 4 初始化用戶管理服務
  • 5 將權限配置傳入包管理器
  • 6 清除代碼路徑不存在的孤立包
  • 7 將系統應用權限從安裝態升級為運行時
  • 8 在掃描應用前,手機供應商的覆蓋安裝包(/overlay)
  • 9 掃描應用目錄,依次為特權系統目錄 priv-app、普通目錄 app、供應商系統目錄 vendor/app等
  • 10 解析存儲管理器
  • 11 如果是第一次開機,需要初始化用戶的默認偏好應用
  • 12 在啟動時,為用戶準備好存儲空間,因為SystemUI等啟動不能等待用戶
  • 13 安裝應用,完成后檢查webview,默認瀏覽器等。
  • 14 啟動PackageInstallerService
  • 15 向系統組件暴露私有服務
    下面我們結合代碼做詳細分析
  • 判斷應用包是否已安裝,如果包名存在于uninstalled_deapp.xml中或者已安裝,則直接返回null。
  • 2.2 下載安裝

    下載安裝可分為兩部分:拷貝應用和安裝應用。拷貝過程的函數調用時序圖如圖2所示。
    【圖2 下載安裝應用程序時序圖】

    frameworks層的入口函數為PackageManager.installPackage,由應用市場APP調用,然后調用PMS.installPackageAsUser,然后發送消息INIT_COPY、MCS_BOUND開始復制,調用HandlerParams.startCopy。這個方法主要分兩部分,一部分是拷貝應用的執行程序,另一部分是創建應用的數據目錄,拷貝部分由handleStartCopy完成。之后調用handlerReturnCode來處理創建數據目錄。拷貝部分會調用DefaultContainerService來完成,該服務為那些可能位于可刪除空間上的文件提供檢查和拷貝功能。當底層設置被移除時,這樣設計可以防止系統進程保留打開的文件時,不被內核殺死。

    handleStartcopy實現在PMS內部類InstallParams中,它的功能是調用遠程方法獲取包信息和安裝位置,如有必要則給與默認車輛覆蓋安裝位置,然后基于安裝位置創建安裝參數。下面我們結合關鍵代碼做進一步分析。

    首先是拷貝應用過程

    • 1 PMS.installPackageAsUser的功能主要是:根據uid確定installFlags,并校驗權限,并構造InstallParam,然后發送INIT_COPY消息。
    @Override public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,int installFlags, String installerPackageName, int userId) {mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);final int callingUid = Binder.getCallingUid();enforceCrossUserPermission(callingUid, userId,true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {try {if (observer != null) {observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);}} catch (RemoteException re) {}return;}if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {installFlags |= PackageManager.INSTALL_FROM_ADB;} else {// Caller holds INSTALL_PACKAGES permission, so we're less strict// about installerPackageName.installFlags &= ~PackageManager.INSTALL_FROM_ADB;installFlags &= ~PackageManager.INSTALL_ALL_USERS;}UserHandle user;if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {user = UserHandle.ALL;} else {user = new UserHandle(userId);}// Only system components can circumvent runtime permissions when installing.if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0&& mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {throw new SecurityException("You need the "+ "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");}if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0|| (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {throw new IllegalArgumentException("New installs into ASEC containers no longer supported");}final File originFile = new File(originPath);final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);final Message msg = mHandler.obtainMessage(INIT_COPY);final VerificationInfo verificationInfo = new VerificationInfo(null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,null /*packageAbiOverride*/, null /*grantedPermissions*/,null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));msg.obj = params;Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",System.identityHashCode(msg.obj));Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(msg.obj));mHandler.sendMessage(msg); }
    • 2 之后根據Handler.doHandleMessage調用到InstallParams.handleStartCopy方法,首先檢查文件和cid是否已生成,如生成則設置installFlags。
    // [InstallParams.handleStartCopy] if (origin.staged) {if (origin.file != null) {installFlags |= PackageManager.INSTALL_INTERNAL;installFlags &= ~PackageManager.INSTALL_EXTERNAL;} else if (origin.cid != null) {installFlags |= PackageManager.INSTALL_EXTERNAL;installFlags &= ~PackageManager.INSTALL_INTERNAL;} else {throw new IllegalStateException("Invalid stage location");} }
    • 3 然后檢查空間大小,如果空間不夠則釋放無用空間。
    // [InstallParams.handleStartCopy] if (!origin.staged && pkgLite.recommendedInstallLocation== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {// TODO: focus freeing disk space on the target devicefinal StorageManager storage = StorageManager.from(mContext);final long lowThreshold = storage.getStorageLowBytes(Environment.getDataDirectory());final long sizeBytes = mContainerService.calculateInstalledSize(origin.resolvedPath, isForwardLocked(), packageAbiOverride);try {mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,installFlags, packageAbiOverride);} catch (InstallerException e) {Slog.w(TAG, "Failed to free cache", e);}if (pkgLite.recommendedInstallLocation== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {pkgLite.recommendedInstallLocation= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;} }
    • 4 覆蓋原有安裝位置的文件,并根據返回結果來確定函數的返回值,并設置installFlags。
    // [InstallParams.handleStartCopy] // Override with defaults if needed. loc = installLocationPolicy(pkgLite); if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE; } else if (!onSd && !onInt) {// Override install location with flagsif (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {// Set the flag to install on external media.installFlags |= PackageManager.INSTALL_EXTERNAL;installFlags &= ~PackageManager.INSTALL_INTERNAL;} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {if (DEBUG_EPHEMERAL) {Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");}installFlags |= PackageManager.INSTALL_INSTANT_APP;installFlags &= ~(PackageManager.INSTALL_EXTERNAL|PackageManager.INSTALL_INTERNAL);} else {// Make sure the flag for installing on external// media is unsetinstallFlags |= PackageManager.INSTALL_INTERNAL;installFlags &= ~PackageManager.INSTALL_EXTERNAL;} }
    • 5 確定是否有任何已安裝的包驗證器,如有,則延遲檢測。主要分三步:首先新建一個驗證Intent,然后設置相關的信息,之后獲取驗證器列表,最后向每個驗證器發送驗證Intent。
    // [InstallParams.handleStartCopy] final Intent verification = new Intent( //構造驗證IntentIntent.ACTION_PACKAGE_NEEDS_VERIFICATION);// ......final PackageVerificationState verificationState = new PackageVerificationState(requiredUid, args);mPendingVerification.append(verificationId, verificationState);// 獲取驗證器列表final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,receivers, verificationState);DeviceIdleController.LocalService idleController = getDeviceIdleController();final long idleDuration = getVerificationTimeout();/** If any sufficient verifiers were listed in the package* manifest, attempt to ask them.*/if (sufficientVerifiers != null) {final int N = sufficientVerifiers.size();if (N == 0) {Slog.i(TAG, "Additional verifiers required, but none installed.");ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;} else {for (int i = 0; i < N; i++) {final ComponentName verifierComponent = sufficientVerifiers.get(i);idleController.addPowerSaveTempWhitelistApp(Process.myUid(),verifierComponent.getPackageName(), idleDuration,verifierUser.getIdentifier(), false, "package verifier");// 向每個驗證器發送驗證Intentfinal Intent sufficientIntent = new Intent(verification);sufficientIntent.setComponent(verifierComponent);mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);}}}
    • 6 向驗證器客戶端發送intent,只有當驗證成功之后才會開啟copy工作。如果沒有任何驗證器則直接拷貝。

    下面為安裝過程入口是PMS.processPendingInstall方法,調用時序圖如圖3
    【圖3 下載安裝-安裝過程圖】

    • 1 首先啟動一個新線程,然后設置安裝信息,處理安裝參數,開始安裝,并發送關于安裝狀態的廣播,然后處理安裝完的事情,比如打印錯誤信息,清除臨時文件等。
    private void processPendingInstall(final InstallArgs args, final int currentStatus) {// Queue up an async operation since the package installation may take a little while.mHandler.post(new Runnable() {public void run() {mHandler.removeCallbacks(this);// Result object to be returnedPackageInstalledInfo res = new PackageInstalledInfo();res.setReturnCode(currentStatus);res.uid = -1;res.pkg = null;res.removedInfo = null;if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {args.doPreInstall(res.returnCode);synchronized (mInstallLock) {installPackageTracedLI(args, res);}args.doPostInstall(res.returnCode, res.uid);//...... }
    • 2 installPackageTracedLI是安裝過程的核心方法,然后調用installPackageLI.首先檢查安裝包的完整性并解析安裝包。
    //[PMS.installPackageLI] // 完整性校驗 if (instantApp && (forwardLocked || onExternal)) {Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked+ " external=" + onExternal);res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);return; }// 檢索包設置,并解析應用 final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY| PackageParser.PARSE_ENFORCE_CODE| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)| (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)| (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0); PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setDisplayMetrics(mMetrics); pp.setCallback(mPackageParserCallback);Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final PackageParser.Package pkg; try {//解析安裝包pkg = pp.parsePackage(tmpPackageFile, parseFlags);DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) {res.setError("Failed parse during installPackageLI", e);return; } finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }
    • 3 檢查SDK版本和沙箱版本,同時檢查是否有靜態共享庫,如有則需要放在內部存儲中。
    //[PMS.installPackageLI] //檢查SDK版本和沙箱版本 if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,"Instant app package must target O");return; } if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {Slog.w(TAG, "Instant app package " + pkg.packageName+ " does not target targetSandboxVersion 2");res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,"Instant app package must use targetSanboxVersion 2");return; } //檢查是否有靜態共享庫 if (pkg.applicationInfo.isStaticSharedLibrary()) {// Static shared libraries have synthetic package namesrenameStaticSharedLibraryPackage(pkg);// No static shared libs on external storageif (onExternal) {Slog.i(TAG, "Static shared libs can only be installed on internal storage.");res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,"Packages declaring static-shared libs cannot be updated");return;} }
    • 4 檢查是否有子安裝包,如有則子安裝包也需要檢測。
    //[PMS.installPackageLI] // If we are installing a clustered package add results for the children if (pkg.childPackages != null) {synchronized (mPackages) {final int childCount = pkg.childPackages.size();for (int i = 0; i < childCount; i++) {PackageParser.Package childPkg = pkg.childPackages.get(i);PackageInstalledInfo childRes = new PackageInstalledInfo();childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);childRes.pkg = childPkg;childRes.name = childPkg.packageName;PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);if (childPs != null) {childRes.origUsers = childPs.queryInstalledUsers(sUserManager.getUserIds(), true);}if ((mPackages.containsKey(childPkg.packageName))) {childRes.removedInfo = new PackageRemovedInfo(this);childRes.removedInfo.removedPackage = childPkg.packageName;childRes.removedInfo.installerPackageName = childPs.installerPackageName;}if (res.addedChildPackages == null) {res.addedChildPackages = new ArrayMap<>();}res.addedChildPackages.put(childPkg.packageName, childRes);}} }
    • 5 檢查安裝包是否已存在,如已存在則需要檢查舊的父包、沙箱、sdk等是否已為空,否則會報錯。
    • 6 校驗安裝包簽名
    //[PMS.installPackageLI] PackageSetting signatureCheckPs = ps; if (pkg.applicationInfo.isStaticSharedLibrary()) {SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);if (libraryEntry != null) {signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);} }// Quick sanity check that we're signed correctly if updating; // we'll check this again later when scanning, but we want to // bail early here before tripping over redefined permissions. if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "+ pkg.packageName + " upgrade keys do not match the "+ "previously installed version");return;} } else {try {verifySignaturesLP(signatureCheckPs, pkg);} catch (PackageManagerException e) {res.setError(e.error, e.getMessage());return;} }
    • 7 設置相關的全向,包括生成權限、移植權限等
    • 8 如果這是一個系統應用,則檢查是否在外部存儲上或是是否被其他應用替換等
    //[PMS.installPackageLI] if (systemApp) {if (onExternal) {// Abort update; system app can't be replaced with app on sdcardres.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,"Cannot install updates to system apps on sdcard");return;} else if (instantApp) {// Abort update; system app can't be replaced with an instant appres.setError(INSTALL_FAILED_INSTANT_APP_INVALID,"Cannot update a system app with an instant app");return;} }
    • 9 生成安裝包Abi(Application binary interface,應用二進制接口,描述應用程序和操作系統之間或其他應用程序的低級接口)
    //[PMS.installPackageLI] try {String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?args.abiOverride : pkg.cpuAbiOverride);final boolean extractNativeLibs = !pkg.isLibrary();derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,extractNativeLibs, mAppLib32InstallDir); } catch (PackageManagerException pme) {Slog.e(TAG, "Error deriving application ABI", pme);res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");return; }
    • 10更新共享庫
    //[PMS.installPackageLI] synchronized (mPackages) {try {updateSharedLibrariesLPr(pkg, null);} catch (PackageManagerException e) {Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());} }
    • 11如有必要,優化dex文件
    //[PMS.installPackageLI] final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)&& !forwardLocked&& !pkg.applicationInfo.isExternalAsec()&& (!instantApp || Global.getInt(mContext.getContentResolver(),Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);if (performDexopt) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); // Do not run PackageDexOptimizer through the local performDexOpt // method because `pkg` may not be in `mPackages` yet. // // Also, don't fail application installs if the dexopt step fails. DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,REASON_INSTALL,DexoptOptions.DEXOPT_BOOT_COMPLETE |DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE); mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,null /* instructionSets */,getOrCreateCompilerPackageStats(pkg),mDexManager.getPackageUseInfoOrDefault(pkg.packageName),dexoptOptions); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }
    • 12替換安裝,則直接安裝新包,這里應用時生成應用數據目錄。ps:替換安裝:其主要過程為更新設置,清除原有的某些APP數據,重新生成相關的app數據目錄等步驟,同事要區分系統應用替換和非系統應用替換。而安裝新包:則直接更新設置,生成APP數據即可。
    try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,"installPackageLI")) {if (replace) {if (pkg.applicationInfo.isStaticSharedLibrary()) {// Static libs have a synthetic package name containing the version// and cannot be updated as an update would get a new package name,// unless this is the exact same version code which is useful for// development.PackageParser.Package existingPkg = mPackages.get(pkg.packageName);if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "+ "static-shared libs cannot be updated");return;}}replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,installerPackageName, res, args.installReason);} else {installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,args.user, installerPackageName, volumeUuid, res, args.installReason);} }
    • 13 如果是安裝一個不存在的包,則調用PMS.installNewPackageLIF方法。首先會檢查是否有重復的包名,并更新設置,然后根據安裝的結果,如果安裝失敗則刪除安裝過程中產生的文件。
    private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,PackageInstalledInfo res, int installReason) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");// Remember this for later, in case we need to rollback this installString pkgName = pkg.packageName;if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);synchronized(mPackages) {final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);if (renamedPackage != null) {// 如果已有相同包名的應用,則報錯res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling package running as "+ renamedPackage);return;}if (mPackages.containsKey(pkgName)) {// Don't allow installation over an existing package with the same name.res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling.");return;}}try {PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, System.currentTimeMillis(), user);updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {prepareAppDataAfterInstallLIF(newPackage);} else {// Remove package from internal structures, but keep around any// data that might have already existeddeletePackageLIF(pkgName, UserHandle.ALL, false, null,PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);}} catch (PackageManagerException e) {res.setError("Package couldn't be installed in " + pkg.codePath, e);}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }
    • 14 然后為已安裝的應用準備數據目錄,其依次的順序是
      • PMS.prepareAppDataAfterInstallLIF
      • PMS.prepareAppDataLIF
      • PMS.prepareAppDataLeafLIF
      • Installer.createAppData

    這個方法是PMS與Installer交互的接口函數,這里的數據目錄是CE類型。

    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {if (DEBUG_APP_DATA) {Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"+ Integer.toHexString(flags));}final String volumeUuid = pkg.volumeUuid;final String packageName = pkg.packageName;final ApplicationInfo app = pkg.applicationInfo;final int appId = UserHandle.getAppId(app.uid);Preconditions.checkNotNull(app.seInfo);long ceDataInode = -1;try {// 調用Installd守護進程的入口ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,appId, app.seInfo, app.targetSdkVersion);} catch (InstallerException e) {//......}// Prepare the application profiles.mArtManagerService.prepareAppProfiles(pkg, userId);if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {// TODO: mark this structure as dirty so we persist it!synchronized (mPackages) {final PackageSetting ps = mSettings.mPackages.get(packageName);if (ps != null) {ps.setCeDataInode(ceDataInode, userId);}}}prepareAppDataContentsLeafLIF(pkg, userId, flags); }
    • 15 如果是替換應用,一般情況是應用更新,或者是重新安裝。它的主要過程包括:驗證簽名,如是系統更新則還需要校驗hash值,檢查共享ID的更改情況,不允許完整更新,更新已被刪除數據,最后根據應用是否是系統應用來判斷接下去的操作。
    private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,UserHandle user, String installerPackageName, PackageInstalledInfo res,int installReason) {final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;final PackageParser.Package oldPackage;final PackageSetting ps;final String pkgName = pkg.packageName;final int[] allUsers;final int[] installedUsers;// ......boolean sysPkg = (isSystemApp(oldPackage));if (sysPkg) {// Set the system/privileged flags as neededfinal boolean privileged =(oldPackage.applicationInfo.privateFlags& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;final int systemPolicyFlags = policyFlags| PackageParser.PARSE_IS_SYSTEM| (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0);replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags,user, allUsers, installerPackageName, res, installReason);} else {replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags,user, allUsers, installerPackageName, res, installReason);} }
    • 16 最后這兩個方法均會調用到PMS.prepareAppDataLeafLIF。
    • 17 安裝完成后,更新設置,更新安裝鎖等。

    2.3 adb安裝

    關于adb安裝,其copy過程與下載安裝不同,但安裝過程卻與下載過程是相同的,這里不做重復分析,需要注意的是adb安裝是不能替換安裝的,具體原因?

    拷貝過程
    其調用時序圖如圖4 所示。
    【圖4 adb安裝-copy過程時序圖】

    • 1 adb的入口在com.android.commands.pm.Pm類,那么這是如何調用到這個類的呢,這是adb命令通過adbd守護進程調用到/system/bin/pm這個腳本,其腳本源碼如下:
    base=/system export CLASSPATh-$base/framework/pm.jar exec app_process $base/bin.com.android.commands.pm.Pm "$@"
    • 2 Pm類通過腳本啟動,執行順序是main->run->runInstall,然后提交session。
    public static void main(String[] args) {int exitCode = 1;try {exitCode = new Pm().run(args);} catch (Exception e) {Log.e(TAG, "Error", e);System.err.println("Error: " + e);if (e instanceof RemoteException) {System.err.println(PM_NOT_RUNNING_ERR);}}System.exit(exitCode); } public int run(String[] args) throws RemoteException {boolean validCommand = false;if (args.length < 1) {return showUsage();}mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));if (mPm == null) {System.err.println(PM_NOT_RUNNING_ERR);return 1;}mInstaller = mPm.getPackageInstaller();mArgs = args;String op = args[0];mNextArg = 1;//......if ("install".equals(op)) {return runInstall();}//...... }
    • 3 Pm.runInstall中首先是創建session,然后提交session,代碼如下。
    private int runInstall() throws RemoteException {long startedTime = SystemClock.elapsedRealtime();final InstallParams params = makeInstallParams();final String inPath = nextArg();if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {File file = new File(inPath);if (file.isFile()) {try {ApkLite baseApk = PackageParser.parseApkLite(file, 0);PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,null, null);params.sessionParams.setSize(PackageHelper.calculateInstalledSize(pkgLite, false,params.sessionParams.abiOverride));} catch (PackageParserException | IOException e) {System.err.println("Error: Failed to parse APK file: " + e);return 1;}} else {System.err.println("Error: Can't open non-file: " + inPath);return 1;}}final int sessionId = doCreateSession(params.sessionParams,params.installerPackageName, params.userId);try {if (inPath == null && params.sessionParams.sizeBytes == -1) {System.err.println("Error: must either specify a package size or an APK file");return 1;}if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {return 1;}Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);if (status.second != PackageInstaller.STATUS_SUCCESS) {return 1;}Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()- startedTime) + " ms");System.out.println("Success");return 0;} finally {try {mInstaller.abandonSession(sessionId);} catch (Exception ignore) {}}}
    • 4 這里Pm相當于客戶端,接受session的服務端在PackageInstallerSession中,這里利用AIDL來完成傳輸,其調用過程為:
      • Pm.doCommitSession
      • PackageInstaller.Session.commit
      • IPackageInstallerSession.commit
      • PackageInstallerSession.commit
      • Handler.Callback.handleMessage
      • PackageInstallerSession.commitLock
      • PMS.installStage

    以上關于session傳遞過程暫不分析,下面我們來詳細看下installStage方法。

    • 5 installStage方法主要功能就是構造InstallParam對象,并發送INIT_COPY。
    void installStage(String packageName, File stagedDir, String stagedCid,IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,String installerPackageName, int installerUid, UserHandle user,Certificate[][] certificates) {if (DEBUG_EPHEMERAL) {if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {Slog.d(TAG, "Ephemeral install of " + packageName);}}final VerificationInfo verificationInfo = new VerificationInfo(sessionParams.originatingUri, sessionParams.referrerUri,sessionParams.originatingUid, installerUid);final OriginInfo origin;if (stagedDir != null) {origin = OriginInfo.fromStagedFile(stagedDir);} else {origin = OriginInfo.fromStagedContainer(stagedCid);}final Message msg = mHandler.obtainMessage(INIT_COPY);final int installReason = fixUpInstallReason(installerPackageName, installerUid,sessionParams.installReason);final InstallParams params = new InstallParams(origin, null, observer,sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,verificationInfo, user, sessionParams.abiOverride,sessionParams.grantedRuntimePermissions, certificates, installReason);params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));msg.obj = params;Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",System.identityHashCode(msg.obj));Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(msg.obj));mHandler.sendMessage(msg); }
    • 6 發送完Handler消息后就與下載安裝過程相同了。

    2.4 本地安裝

    本地安裝參與對象包括PackageInstaller應用,PMS兩部分。下面我們就來分析下PackageInstaller是如何調用到PMS中的。函數調用時序圖如圖5所示。
    【圖5 本地安裝前提調用時序圖】

    • 1 點擊文件管理器中的apk文件時,會調用到FolderFragment類的openFile方法,然后調用startActivitySafety方法啟動PackageInstallerActivity。
    private void openFile(File f) { final Uri fileUri = Uri.fromFile(f); final Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.putExtra(Intent.EXTRA_TITLE, f.getName()); intent.putExtra(EXTRA_ALL_VIDEO_FOLDER, true); Uri contentUri = null; String type = getMIMEType(f); //...... if (contentUri != null) { intent.setDataAndType(contentUri, type); } else { intent.setDataAndType(fileUri, type); } try { startActivitySafely(intent); } //...... }
    • 2 如下為PackageInstallerActivity.onCreate方法源碼,其主要過程初始化各個服務的成員變量如PMS,校驗session,并加載UI界面,然用戶確定是否安裝。
    //[PackageInstallerActivity.java] protected void onCreate(Bundle icicle) {super.onCreate(icicle);if (icicle != null) {mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);}//初始化各個關鍵參數mPm = getPackageManager();mIpm = AppGlobals.getPackageManager();mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);mInstaller = mPm.getPackageInstaller();mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);final Intent intent = getIntent();mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,PackageInstaller.SessionParams.UID_UNKNOWN);mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)? getPackageNameForUid(mOriginatingUid) : null;final Uri packageUri;//校驗sessionif (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");finish();return;}mSessionId = sessionId;packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));mOriginatingURI = null;mReferrerURI = null;} else {mSessionId = -1;packageUri = intent.getData();mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);}// if there's nothing to do, quietly slip into the etherif (packageUri == null) {Log.w(TAG, "Unspecified source");setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);finish();return;}if (DeviceUtils.isWear(this)) {showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);return;}boolean wasSetUp = processPackageUri(packageUri);if (!wasSetUp) {return;}// 加載UI界面bindUi(R.layout.install_confirm, false);checkIfAllowedAndInitiateInstall(); }
    • 3 當用戶點擊安裝按鈕時,響應函數為PackageInstallerActivity.onClick方法,
    //[PackageInstallerActivity.java] public void onClick(View v) {if (v == mOk) {if (mOk.isEnabled()) {if (mOkCanInstall || mScrollView == null) {if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, true);finish();} else {startInstall();}} else {mScrollView.pageScroll(View.FOCUS_DOWN);}}} else if (v == mCancel) {// Cancel and finishsetResult(RESULT_CANCELED);if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, false);}finish();} }
    • 4 之后調用 PackageInstallerActivity.startInstall方法,構造Intent,然后啟動InstallInstalling,并銷毀PackageInstallerActivity。
    private void startInstall() {// Start subactivity to actually install the applicationIntent newIntent = new Intent();newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,mPkgInfo.applicationInfo);newIntent.setData(mPackageURI);newIntent.setClass(this, InstallInstalling.class);String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);if (mOriginatingURI != null) {newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);}if (mReferrerURI != null) {newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);}if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);}if (installerPackageName != null) {newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,installerPackageName);}if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);}if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);startActivity(newIntent);finish(); }
    • 5 之后啟動InstallInstalling,因為Activity中的默認成員方法的執行順序是onCreate->onStart->onResume...其中onCreate的方法中主要過程包括:
      • 1 獲取待安裝應用信息
      • 2 根據應用安裝與否決定如何調用方法
      • 3 如果已存在,則直接調用PackageManager.installExistingPackage
      • 4 如果不存在則構造session
      • 5 之后則為安裝事件廣播添加一個監測
    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.install_installing);// 獲取待安裝應用信息ApplicationInfo appInfo = getIntent().getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);mPackageURI = getIntent().getData();// 如果應用已存在,則使用這條路徑安裝if ("package".equals(mPackageURI.getScheme())) {try {getPackageManager().installExistingPackage(appInfo.packageName);launchSuccess();} catch (PackageManager.NameNotFoundException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}} else { //否則使用session提交安裝應用final File sourceFile = new File(mPackageURI.getPath());PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo,sourceFile), R.id.app_snippet);// 如果session已存在,則獲取sessionId等數據if (savedInstanceState != null) {mSessionId = savedInstanceState.getInt(SESSION_ID);mInstallId = savedInstanceState.getInt(INSTALL_ID);// Reregister for result; might instantly call back if result was delivered while// activity was destroyedtry {InstallEventReceiver.addObserver(this, mInstallId,this::launchFinishBasedOnResult);} catch (EventResultPersister.OutOfIdsException e) {// Does not happen}} else { // 否則創建sessionPackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);// ......try {mInstallId = InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,this::launchFinishBasedOnResult);} catch (EventResultPersister.OutOfIdsException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}//創建sessiontry {mSessionId = getPackageManager().getPackageInstaller().createSession(params);} catch (IOException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}}//......mSessionCallback = new InstallSessionCallback();} }
    • 6 InstallInstalling.onStart中注冊回調函數,然后onResume中執行AsyncTask。
    @Override protected void onResume() {super.onResume();// This is the first onResume in a single life of the activityif (mInstallingTask == null) {PackageInstaller installer = getPackageManager().getPackageInstaller();PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);//如果session非空,則執行AsyncTaskif (sessionInfo != null && !sessionInfo.isActive()) {mInstallingTask = new InstallingAsyncTask();mInstallingTask.execute();} else {// we will receive a broadcast when the install is finishedmCancelButton.setEnabled(false);setFinishOnTouchOutside(false);}} }
    • 7 AsyncTask是Android提供的一種輕量級的異步類,執行過程可以表示為5個階段。
      • 1 準備執行,onPreExecute()
      • 2 正在后臺執行,doInBackgroud()
      • 3 進度更新,onProcessUpdate()
      • 4 完成后臺任務,onPostExecute()
      • 5 取消任務,onCacelled()

    此處重寫了方法onPostExecute方法,源碼如下。

    @Override protected void onPostExecute(PackageInstaller.Session session) {if (session != null) {Intent broadcastIntent = new Intent(BROADCAST_ACTION);broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);broadcastIntent.setPackage(getPackageManager().getPermissionControllerPackageName());broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);PendingIntent pendingIntent = PendingIntent.getBroadcast(InstallInstalling.this,mInstallId,broadcastIntent,PendingIntent.FLAG_UPDATE_CURRENT);//提交sessionsession.commit(pendingIntent.getIntentSender());mCancelButton.setEnabled(false);setFinishOnTouchOutside(false);} else {getPackageManager().getPackageInstaller().abandonSession(mSessionId);if (!isCancelled()) {launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);}} }
    • 8 session對象傳輸順序為:
      • 1 PackageInstaller.Session.commit
      • 2 IPackageInstallerSession.commit
      • 3 PackageInstallerSession.commit
      • 4 Handler.Callback.handleMessage
      • 5 PackageInstallerSession.commitLock
      • 6 PMS.installStage
        這里是不是似曾相識,這一步跟Adb安裝的第4步幾乎相同,之后就調用installStage方法完成安裝。

    #3 總結

    安裝應用的場景就是上述所示的PMS構造函數安裝、adb安裝、網絡下載安裝、本地安裝。其最終的入口為PMS.prepareAppDataLeafLIF,然后調用Installer類完成安裝,這里涉及到System_server到Installd守護進程的轉移。

    轉載于:https://www.cnblogs.com/z1987/p/8974719.html

    總結

    以上是生活随笔為你收集整理的Android中应用安装分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    亚洲欧美综合精品久久成人 | 国产流白浆高潮在线观看 | 91看片一区二区三区 | 九九久久电影 | 国产成人久久 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 91中文在线| 超碰在线官网 | 免费在线观看av片 | 狠狠干天天 | 亚洲精品xxxx| 免费a视频| 国产一区在线播放 | 激情视频久久 | 日韩激情免费视频 | 中文字幕美女免费在线 | 亚洲日韩欧美一区二区在线 | av丁香花| 狠狠狠色丁香婷婷综合激情 | 91亚洲视频在线观看 | 国产黄色a | 九九免费在线看完整版 | 国产精品美女久久久久久久久 | 午夜 久久 tv| 最近免费在线观看 | 色综合www | 天天操操操操操 | 亚洲 成人 欧美 | 欧美精品久久久久久久久久白贞 | 国内精品久久久久影院一蜜桃 | 97国产小视频 | 精品视频在线免费观看 | 精品一区二区免费在线观看 | 亚洲最快最全在线视频 | 日韩av一区二区在线影视 | 毛片随便看| 久久这里只有精品视频99 | 国产理论影院 | 久久久久综合网 | 亚洲高清精品在线 | 久久久久久久久久久久久久免费看 | 国产色婷婷精品综合在线手机播放 | 久久久久久国产一区二区三区 | 一区二区三区免费网站 | 国产一区视频免费在线观看 | 91精品亚洲影视在线观看 | 欧美综合干 | www.狠狠色| 又黄又爽又色无遮挡免费 | 中文字幕美女免费在线 | 超碰97免费观看 | 日韩字幕 | 国产中年夫妇高潮精品视频 | 久久精品一二三区白丝高潮 | 香蕉在线观看视频 | 99免费观看视频 | 国产精品久久久久久一区二区三区 | 欧美日韩高清在线观看 | 久久露脸国产精品 | 日本精a在线观看 | 国产精品视频区 | 国产色啪 | 在线观看亚洲精品 | 最新国产精品拍自在线播放 | 美国三级黄色大片 | 日韩电影一区二区在线 | 欧美激情视频三区 | 免费日韩 精品中文字幕视频在线 | 91九色视频在线观看 | 欧美不卡视频在线 | 午夜a区| 亚洲精品66 | 九七在线视频 | 97人人模人人爽人人喊网 | 丁香六月久久综合狠狠色 | 国产精品久久久久久久久久 | 久久久久久国产一区二区三区 | 九七视频在线观看 | 免费男女羞羞的视频网站中文字幕 | 在线观看视频福利 | 高清国产午夜精品久久久久久 | 精品一二区 | www.色婷婷.com| 国产一区二区综合 | 亚洲最新在线 | 国产精品欧美激情在线观看 | 欧美巨乳波霸 | 国产亚洲精品精品精品 | 麻豆高清免费国产一区 | 日本xxxxav| 天堂网一区二区三区 | 精品a视频 | 中文字幕av专区 | 国产亚洲在线视频 | 日本久久91 | 四虎成人精品 | 91久久久久久久一区二区 | 国产一级在线观看视频 | 日日操日日| 欧美激情精品久久久久久变态 | 成人av免费 | av片在线看| 精品在线二区 | 伊人网站 | 国产在线播放一区二区三区 | 国产免费视频在线 | 日韩欧美成 | 精品一二区 | 久久久久久黄色 | 91中文在线视频 | 综合色天天| 五月婷婷激情综合 | 99免费视频 | 国产精品自产拍在线观看桃花 | 在线观看一二三区 | 日韩免费在线观看 | 亚洲欧美精品一区 | 天天玩夜夜操 | 午夜视频黄 | 国产一二区视频 | 日韩在线视频不卡 | 免费网站观看www在线观看 | 欧美精品久久天天躁 | 久久99久久99免费视频 | 国产一级性生活 | 中文在线天堂资源 | 最近中文字幕完整高清 | 日韩在线中文字幕 | 69精品人人人人 | 日韩高清av在线 | 在线欧美小视频 | 99精品国产一区二区三区不卡 | 亚洲在线视频播放 | 91成人区| 亚洲欧美日韩一二三区 | 97视频亚洲 | 99视频在线精品免费观看2 | 六月丁香色婷婷 | 亚洲国产中文字幕在线观看 | 久久精久久精 | 国产一区高清在线观看 | 国产美女永久免费 | 久久精品小视频 | 天天爱天天操天天射 | 国产精品免费一区二区三区 | 亚洲精品资源在线 | 国产亚洲人成网站在线观看 | 精品视频在线视频 | 久久久免费精品国产一区二区 | 人人干人人干人人干 | 国产视频1区2区3区 久久夜视频 | 日本丰满少妇免费一区 | 成人久久 | 国产一线二线三线在线观看 | 国产精品免费久久久久久久久久中文 | 91久久国产综合精品女同国语 | 在线欧美a | 亚洲伦理中文字幕 | 免费黄色小网站 | 久久人人爽人人爽人人片av软件 | 中文字幕av全部资源www中文字幕在线观看 | www蜜桃视频 | 麻豆视频91 | 免费日韩 精品中文字幕视频在线 | 成+人+色综合 | 国产午夜av | 在线激情网 | 九九九在线观看 | 国产伦理一区 | 手机av观看| 国产午夜一区 | 91女人18片女毛片60分钟 | 婷婷精品国产一区二区三区日韩 | 超碰国产97 | 久久国产精品视频观看 | 欧美成a人片在线观看久 | 久久精品国产99国产 | 国产69精品久久久久99尤 | 国产第一页在线播放 | 99 色 | 99热超碰在线| 最近中文字幕国语免费av | 欧美色图30p | 天天综合网在线观看 | 精品国产一区二区三区久久久久久 | 欧美精品久久 | 国产午夜精品一区二区三区嫩草 | 久久久久久久久久网站 | 天天操天天色天天射 | 久久综合爱 | 日韩激情av在线 | 国产麻豆果冻传媒在线观看 | 日韩理论片在线 | 欧美成人黄 | 久久影院亚洲 | 久久电影网站中文字幕 | 亚洲视频一 | 欧美日韩在线视频观看 | 日韩在线视频二区 | 久久久久久综合网天天 | 97国产大学生情侣白嫩酒店 | 黄色av一级片 | 99re国产 | 欧美一级欧美一级 | 97在线观看视频免费 | 日本精品视频在线 | 天堂麻豆| 国产精品99久久久久久人免费 | 日韩av看片 | 国产精品国产毛片 | wwwww.国产 | jizzjizzjizz亚洲 | 四虎国产精品免费 | 久久精品欧美一区 | 久久一二三四 | 在线有码中文字幕 | 91手机电影| 在线三级中文 | 在线观看午夜av | 久久情网 | 色婷婷六月| 伊人天堂av| 久久精品1区 | 国产一级片直播 | 999久久久久久 | 欧美大片第1页 | 不卡的一区二区三区 | 91九色国产蝌蚪 | 99热9| 激情www | 国产精品一区二区在线观看免费 | 奇米网777| 婷婷丁香导航 | 国产精品成人久久久 | 国产最新视频在线观看 | 超碰资源在线 | av在线一级 | 国产精品99久久久 | 2020天天干夜夜爽 | 韩日成人av| www.天天射.com | 日韩在线电影一区二区 | 国产精品成人久久久久 | 91大神dom调教在线观看 | 亚洲狠狠丁香婷婷综合久久久 | 国产精品美女久久久久久久网站 | 中文字幕精品一区 | 丁香久久婷婷 | 丁香六月欧美 | 欧美另类重口 | 天天天天综合 | .国产精品成人自产拍在线观看6 | 一级一片免费看 | 一区二区三区免费在线 | 中文字幕一区二区在线观看 | 狠狠操狠狠干天天操 | 免费的黄色的网站 | 中文字幕网站视频在线 | 激情伊人| 天天草综合 | 中文字幕影片免费在线观看 | 国产免费久久 | 青青看片 | 激情综合五月网 | 91av在线不卡 | 亚洲婷婷免费 | 欧美人交a欧美精品 | 亚洲三级影院 | 一区二区不卡视频在线观看 | 欧美精品免费在线观看 | 午夜国产一区 | 日韩精品一区二区三区外面 | 免费在线播放黄色 | 天天做夜夜做 | 久久99亚洲网美利坚合众国 | 中文字幕乱视频 | 国产精品视频全国免费观看 | 国产一区免费在线 | 久久超 | 韩国av永久免费 | 操操综合网 | 午夜视频播放 | 国产亚洲精品久久久久久久久久久久 | 福利视频一区二区 | 在线韩国电影免费观影完整版 | 超碰在线人 | av电影不卡在线 | 成人一区在线观看 | 不卡精品视频 | 欧美日韩一区二区三区不卡 | 久久好看免费视频 | www.日本色 | 久久你懂的 | 狠狠干夜夜爱 | www欧美色| 亚洲精品456在线播放第一页 | 久久精品79国产精品 | 久草视频观看 | 91视频啊啊啊 | 久久免费的精品国产v∧ | 中文成人字幕 | 国产精品日韩欧美 | 日韩av男人的天堂 | 婷婷深爱五月 | 91人人在线 | 天天想夜夜操 | 中文字幕在线视频精品 | 国内精品久久久久久久影视简单 | 亚洲精品视频网 | 久久尤物电影视频在线观看 | 精品免费国产一区二区三区四区 | 国产h在线播放 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 色婷婷电影 | 亚洲精品一区二区精华 | 四虎伊人| 在线看日韩 | 国产精品久久久免费看 | 国产色区 | 一区二区 精品 | 国产精品黄色影片导航在线观看 | 91九色成人蝌蚪首页 | 婷婷在线免费观看 | 成人网页在线免费观看 | 黄色毛片电影 | 日韩免费福利 | 午夜12点 | 99视频在线观看一区三区 | 久久国内精品99久久6app | 午夜国产一区二区三区四区 | av视屏在线 | 亚洲综合色丁香婷婷六月图片 | 成人永久免费 | 亚洲日本va午夜在线影院 | 日韩在线三级 | 国产高清免费在线观看 | 在线免费黄色av | 久久免费视频国产 | 色综合狠狠干 | 久久久久成人精品 | 中文字幕 婷婷 | 国产黄色视| 亚洲精品国产精品国产 | 久久精品视频在线免费观看 | 00av视频| 久久久婷 | 996久久国产精品线观看 | 欧美黄色免费 | 成人午夜片av在线看 | 欧美一区二区三区在线播放 | 天无日天天操天天干 | 1024久久 | 成人黄色大片在线观看 | 色婷五月天| 亚洲国产美女精品久久久久∴ | 日本韩国精品在线 | va视频在线观看 | 西西4444www大胆视频 | 精品视频资源站 | 国产成人精品aaa | free,性欧美 九九交易行官网 | 91资源在线免费观看 | 日韩欧美在线观看一区二区三区 | 亚洲韩国一区二区三区 | 国产精品久久久精品 | 日韩视频免费观看高清完整版在线 | 亚洲精品国产品国语在线 | 久久免费视频6 | 狠狠狠狠狠狠干 | 亚洲第五色综合网 | 色天天综合网 | 国产精品美女www爽爽爽视频 | 韩国精品福利一区二区三区 | 国产精品美女久久久久久2018 | 97电影在线观看 | 久久tv | 国产爽视频 | 午夜视频在线观看一区二区 | 日韩欧美一区二区三区视频 | 精品一区二区免费在线观看 | 色视频在线观看 | 超碰人人射 | 亚洲精品免费在线 | 天天操夜夜逼 | 日韩成人黄色 | 国产精品美乳一区二区免费 | 99麻豆久久久国产精品免费 | 午夜黄色 | 亚洲国产中文在线观看 | 亚洲国产日韩一区 | 人人爽人人乐 | 日本成人a| 国产精品入口久久 | 国产视频一区二区在线 | 国产小视频福利在线 | 91大神精品视频在线观看 | www欧美色 | 国产免费又粗又猛又爽 | 亚洲精品美女在线观看播放 | 国产精品网在线观看 | av线上免费看 | 999视频网| 天天射天天干天天 | 久久久久免费精品视频 | 色妞色视频一区二区三区四区 | 又污又黄的网站 | 国偷自产视频一区二区久 | 久久久久福利视频 | 五月婷婷色 | 久久任你操 | 在线 影视 一区 | 99国产在线视频 | 欧美精品亚洲精品日韩精品 | 一本—道久久a久久精品蜜桃 | 亚洲免费av观看 | 日韩午夜高清 | 久久婷五月 | 超碰com | 免费国产黄线在线观看视频 | 成人a大片 | 久久成年人| 天天操天天是 | 久影院| 在线观看色网站 | 国产又粗又猛又爽又黄的视频先 | 麻豆视频免费在线观看 | 国产精品av免费在线观看 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 九九热精品国产 | 成人中文字幕av | 波多野结衣精品 | 久久久这里有精品 | 在线中文字幕av观看 | 午夜精品视频免费在线观看 | 久久久精品欧美一区二区免费 | 狠狠操综合 | 91在线porny国产在线看 | 精品99999 | 中文字幕 欧美性 | 日韩国产欧美视频 | 中文字幕 在线 一 二 | 久草香蕉在线视频 | 麻豆94tv免费版 | 天天爱天天操天天干 | 国产午夜三级一区二区三桃花影视 | 日韩在线高清视频 | 亚洲一级特黄 | 在线播放视频一区 | 黄色成年网站 | 国产黄色免费在线观看 | 在线观看香蕉视频 | 91亚洲精品久久久 | 丰满少妇麻豆av | 99精品免费在线观看 | 天天草av | 国产精品午夜在线观看 | 成人av观看 | 国产69精品久久久久99 | 麻豆成人在线观看 | 国产精品久久久久婷婷 | 国产一区二区在线看 | 天天天干天天射天天天操 | 久久久久久久久久久综合 | 日韩精品一区二区在线观看 | 久久精品牌麻豆国产大山 | 999国内精品永久免费视频 | 成人网页在线免费观看 | 久热香蕉视频 | 国产一区在线视频播放 | 91成版人在线观看入口 | 91av免费在线观看 | 色多多污污 | 午夜精品一区二区三区四区 | 国产999精品久久久久久麻豆 | 91日韩在线播放 | 日韩欧美在线免费 | 国产精品wwwwww| 欧美91精品久久久久国产性生爱 | 日韩视频中文字幕在线观看 | 国产色拍拍拍拍在线精品 | 麻豆国产精品va在线观看不卡 | 国产精品欧美日韩 | h动漫中文字幕 | 黄色小视频在线观看免费 | 视频在线观看国产 | www操操| 日日噜噜噜噜夜夜爽亚洲精品 | 四虎永久免费在线观看 | www.99久久.com| 韩国三级av在线 | 日本精品小视频 | 狠狠躁夜夜躁人人爽超碰91 | 日韩女同一区二区三区在线观看 | 中国一级片视频 | 国产免费a | 久久精美视频 | 欧美精品小视频 | 欧美激情精品久久久 | 国产网站av | 成人欧美日韩国产 | 全久久久久久久久久久电影 | 天天搞天天干 | 日韩av免费一区 | 欧美性性网 | 国产在线精品一区二区 | 久久超级碰 | 久久婷婷久久 | 成人久久影院 | 日韩精品视频第一页 | 91精品国产欧美一区二区 | 久久午夜色播影院免费高清 | 日韩视频1区 | 91在线看黄 | 在线精品视频在线观看高清 | 中文字幕永久在线 | 色婷婷视频在线 | 91精品在线观看视频 | 69久久99精品久久久久婷婷 | 四虎影视成人永久免费观看亚洲欧美 | 999久久a精品合区久久久 | 婷婷丁香激情综合 | 99久久久久成人国产免费 | 亚洲伦理一区 | 国产成人三级一区二区在线观看一 | 欧美男男激情videos | 深爱激情综合网 | 久久香蕉国产精品麻豆粉嫩av | av黄色免费看 | 福利视频网址 | 日本中文字幕系列 | 蜜臀精品久久久久久蜜臀 | 婷婷在线播放 | 亚洲午夜电影网 | av一二三区| 亚洲精品国偷拍自产在线观看 | 亚洲电影毛片 | 亚洲成人av片 | 亚洲欧洲一级 | 天天干天天玩天天操 | 五月婷婷视频在线 | 99在线观看精品 | 国产尤物视频在线 | 国内精品久久久久久久影视简单 | 精品 一区 在线 | 精品视频免费在线 | 91污视频在线观看 | 在线观看www91 | 久久综合狠狠综合久久狠狠色综合 | 99久久久久久国产精品 | 国产精品免费麻豆入口 | 免费中午字幕无吗 | 欧美性色黄大片在线观看 | 国产97碰免费视频 | 美女一二三区 | 天天干天天干 | 日本精品视频在线观看 | 国产精品免费视频观看 | 日韩在线视频看看 | 97色se| 亚洲黄色网络 | 成人啪啪18免费游戏链接 | 中文字幕免费成人 | 久久呀 | 成人黄色大片在线观看 | 天海冀一区二区三区 | 久久在线免费观看视频 | 国产一卡二卡四卡国 | 欧美国产在线看 | 国产精品中文字幕av | 日韩精品一卡 | 亚洲,国产成人av | 免费看的黄色小视频 | av综合网址 | 99色免费| 免费男女羞羞的视频网站中文字幕 | 久久夜靖品 | 最近日本韩国中文字幕 | 日韩资源在线 | 亚洲精品欧美精品 | 激情网站免费观看 | 国产精品久久久久久久久久久久久久 | 狠狠干狠狠久久 | 韩国精品在线观看 | 一区二区三区久久 | 国产一区二区在线精品 | 国产黄色免费在线观看 | 欧美日韩一区二区视频在线观看 | 国产一卡二卡四卡国 | 亚洲精品午夜aaa久久久 | 97久久精品午夜一区二区 | 国产一及片| 亚洲综合在线播放 | 亚洲成av人影片在线观看 | 亚洲午夜久久久久 | 国产精品免费一区二区三区 | av久久久久久| 激情综合国产 | 久久激情五月丁香伊人 | 成人av观看 | 国产护士av | 一区在线播放 | 精品久久久网 | 精品毛片在线 | 99久久久免费视频 | 亚洲激情视频在线 | 久久精品视频免费观看 | 色婷婷在线观看视频 | 午夜av日韩| 国产护士在线 | 青春草视频| 中文一区在线 | 成人影片免费 | 日韩字幕 | 三级av小说 | 日韩精品中文字幕在线观看 | 少妇bbw揉bbb欧美 | 国产欧美日韩一区 | 国产成人精品久久二区二区 | av韩国在线 | 亚洲免费国产视频 | 国产视频欧美视频 | 欧美日韩一区二区三区免费视频 | 91视频高清免费 | 最新真实国产在线视频 | 欧美精品国产精品 | v片在线看 | 免费男女羞羞的视频网站中文字幕 | 伊人国产在线观看 | 久久一区精品 | 国产精品国产三级国产aⅴ入口 | 日韩精品久久久久 | 中文字幕 国产视频 | 日韩美视频| 婷婷六月综合亚洲 | 亚洲精品美女在线 | 久艹视频在线观看 | 国产福利小视频在线 | 久久69精品久久久久久久电影好 | 日韩一二区在线观看 | 久久福利在线 | 超碰资源在线 | 成人久久久久久久久 | 亚洲视频每日更新 | 国产精品小视频网站 | 国产99亚洲| 亚洲一区美女视频在线观看免费 | 91亚洲精品在线观看 | 在线三级av | 日产中文字幕 | 日韩视频在线不卡 | 中文字幕三区 | 国产精品99久久久久久小说 | 天堂中文在线播放 | 成人黄色国产 | 夜夜夜| 不卡视频一区二区三区 | av综合在线观看 | 久久久激情视频 | 亚洲国产精久久久久久久 | 91免费在线看片 | 国产精品视频你懂的 | 欧美日韩国产高清视频 | 国产精品毛片久久久久久久久久99999999 | 日韩 在线观看 | 国产视频不卡一区 | 江苏妇搡bbbb搡bbbb | 国产精品久久久久9999吃药 | 五月婷婷综合久久 | www成人av| 亚洲国产网站 | av网站手机在线观看 | 日韩精品影视 | 午夜视频一区二区三区 | 久久久久久久国产精品影院 | 一区二区三区免费在线播放 | 国产亚洲欧美一区 | 悠悠av资源片 | 欧美日韩国产高清视频 | 国产v在线观看 | 97精产国品一二三产区在线 | 久久免费99 | 久久色在线观看 | 99久久久久成人国产免费 | 美女福利视频网 | 精品专区一区二区 | 久久久久久久福利 | 久久不射电影院 | 麻豆视频在线看 | 五月天国产 | 免费毛片aaaaaa | 免费看成年人 | 在线激情av电影 | 亚州欧美精品 | 亚洲综合激情五月 | 综合久久影院 | www天天干 | 激情网五月天 | 精品在线看 | 欧美国产91 | 超碰97人 | 亚洲va欧美| 国产亚洲精品成人av久久ww | 91av在线免费看 | 黄色a视频 | 99精品视频免费全部在线 | 欧美精品少妇xxxxx喷水 | 中文字幕亚洲情99在线 | 在线观看黄色免费视频 | 欧美日韩国产在线 | 国产不卡在线观看视频 | 久久综合九九 | 午夜三级毛片 | 国产精品久99 | 久久高清精品 | 欧美日韩精品网站 | 激情五月婷婷综合网 | 免费日韩一级片 | 91av在线视频免费观看 | 国产精品美女免费 | 国产主播大尺度精品福利免费 | 五月天激情综合 | 成年人免费在线看 | 欧美老人xxxx18| 成人在线观看资源 | 久久久久欠精品国产毛片国产毛生 | 精品国产一区二区久久 | 久操视频在线 | 麻豆视频观看 | 日日日视频 | av观看在线观看 | 色综合久久88色综合天天人守婷 | 日本性xxxxx| 久久精品99精品国产香蕉 | 久久久高清 | 日韩深夜在线观看 | 国产精品 中文在线 | 97人人澡人人添人人爽超碰 | www.午夜视频 | 国产精品免费看 | 成人av在线亚洲 | 爱色婷婷 | 久久精品久久国产 | 欧美色图30p | 日本在线观看视频一区 | 久久欧洲视频 | 免费亚洲婷婷 | 999毛片 | 精品在线观看一区二区 | 麻豆一级视频 | 亚洲精品国偷自产在线91正片 | 成人在线黄色电影 | 精品久久久久久久久久岛国gif | 欧美极品在线播放 | 人人玩人人爽 | 欧美激情视频一区二区三区免费 | 人人草网站 | 久久久久久久久久伊人 | 国产99一区| 久久久婷| 中文字幕一区二区三区久久蜜桃 | 成人免费视频网站在线观看 | 国产69精品久久app免费版 | 五月婷婷六月丁香 | 综合色天天 | av韩国在线 | 视频在线亚洲 | 国产一区二区三区高清播放 | 亚洲精品一区二区三区在线观看 | 久久综合九色综合欧美狠狠 | 亚洲激情中文 | 久久久黄视频 | 福利视频导航网址 | 久久99精品国产 | 91福利试看 | 在线小视频 | 亚洲另类人人澡 | 天天插天天操天天干 | 98久久| 91网站免费观看 | 日韩视频一 | 99久久综合狠狠综合久久 | 久久国产精品一区二区三区 | 黄色av电影在线观看 | 婷婷在线不卡 | 亚洲精品18日本一区app | 日批视频国产 | 亚洲一片黄 | 美女精品久久久 | 欧美日韩在线第一页 | 免费看三级黄色片 | 久久久在线视频 | 色综合色综合色综合 | 免费观看的av | 91在线观 | 国产中文字幕在线免费观看 | 免费看网站在线 | 久久免费视频3 | 成人黄在线观看 | 特级aaa毛片 | 国内精品久久久久影院优 | 久久天天躁 | 黄网站www| av 一区 二区 久久 | 天天射天天干天天爽 | av电影免费在线播放 | 超碰公开在线观看 | 久久成人国产精品入口 | 四虎免费av| 欧美色综合 | 日韩精品久久久久久久电影99爱 | av黄色av| 国产一区免费观看 | 一区中文字幕在线观看 | 91免费在线看片 | 色国产在线 | 色综合欧洲 | 亚洲 欧美 精品 | 91女神的呻吟细腰翘臀美女 | 国产成人一级 | 99久免费精品视频在线观看 | 玖玖在线观看视频 | 日日夜夜婷婷 | 一区二区三区四区精品视频 | 男女激情网址 | 久久久久国产精品视频 | 97精品伊人 | 激情五月在线视频 | 97色婷婷| 日韩精品综合在线 | 一区二区三区在线观看免费 | 亚洲欧美日本国产 | 国产精品v a免费视频 | 黄视频色网站 | 午夜国产影院 | 欧美精品v国产精品v日韩精品 | 国产精品6999成人免费视频 | 91 在线视频播放 | 国内一级片在线观看 | 亚洲精品成人 | 狠狠色丁香久久婷婷综合五月 | av看片网址 | av女优中文字幕在线观看 | 美女精品 | 亚洲一二视频 | 国产日韩中文字幕在线 | 国内精品久久久久久久久久久久 | 天天爽夜夜爽人人爽一区二区 | 二区三区在线视频 | 在线国产小视频 | 国产精品久久久久久模特 | 一区二区三区四区精品 | 91黄色成人 | 亚洲免费av一区二区 | 国产一级特黄毛片在线毛片 | 国产精品99久久久精品免费观看 | 国产在线精品视频 | 91精品国产99久久久久久红楼 | 久久草网站 | 337p西西人体大胆瓣开下部 | 成人在线视频免费看 | 99在线免费视频观看 | 亚洲精品中文字幕在线观看 | 亚洲 成人 一区 | 成人一级黄色片 | av在线精品 | 国产精品美乳一区二区免费 | 日韩黄在线观看 | 国产裸体视频bbbbb | 免费看片网站91 | 五月天,com| 国产在线观看一 | 天堂在线视频中文网 | 婷婷色中文网 | 免费观看一区二区 | 天天操天天怕 | 玖玖视频精品 | 久久精品精品电影网 | 成人av免费在线播放 | 久久国产精品99久久久久久丝袜 | 日韩精品一区二区在线视频 | 五月婷婷色综合 | 日韩大片在线免费观看 | 成人a级免费视频 | 97超碰超碰久久福利超碰 | 亚洲精品在线观看免费 | 狠狠色丁香婷婷综合橹88 | 天天色天| 亚洲精品在线免费观看视频 | 国产精品成人免费一区久久羞羞 | avhd高清在线谜片 | www黄色软件 | 欧美日韩伦理在线 | 日韩欧美一区二区三区在线观看 | 日韩一区二区三区高清在线观看 | 99热国产在线观看 | 9在线观看免费高清完整版在线观看明 | 欧美黄色免费 | 久久久免费高清视频 | 男女啪啪免费网站 | 国产精品九九久久久久久久 | 欧美激情视频一二区 | 91精品久久久久久久91蜜桃 | 在线观看国产亚洲 | 超碰.com| 国产精品女人久久久 | 黄色日视频 | 欧洲黄色片 | 99riav1国产精品视频 | 91看片在线看片 | 免费黄色在线 | 欧美久久久久久久久久久久 | 国产日韩精品在线 | 中文字幕 婷婷 | 欧美一区二区日韩一区二区 | 99精品国产视频 | 久久精品爱爱视频 | a午夜电影 | 国产视频97 | 精品嫩模福利一区二区蜜臀 | 国产码电影 | 成人欧美一区二区三区黑人麻豆 | av五月婷婷 | 亚洲综合小说电影qvod | 在线电影91| 午夜精品久久久久久久99水蜜桃 | 射综合网 | 国产真实精品久久二三区 | 日本黄色免费播放 | 国产一区二区播放 | 97超碰.com| 欧美-第1页-屁屁影院 | 一区二三国产 | 精品在线观看一区二区三区 | 美女视频黄频 | 国产日韩av在线 | 日韩精品aaa | 久久国产一二区 | 人人添人人澡 | 亚洲乱码国产乱码精品天美传媒 | 91九色视频国产 | 超碰大片| 亚洲国产精久久久久久久 | 国产福利91精品张津瑜 | 韩国av永久免费 | 91禁在线看 | 99亚洲精品在线 | 日韩欧美亚州 | 91精品无人成人www | 精一区二区 | 国产97视频在线 | 91精品办公室少妇高潮对白 | 国产在线播放一区二区 | 97精品在线 | www黄色软件| av黄色免费看 | 婷婷综合国产 | 久久激五月天综合精品 | 国产精品大片 | 欧美激情视频一二区 | 在线欧美最极品的av | 久久国产精品精品国产色婷婷 | 青青色影院| 一本大道久久精品懂色aⅴ 五月婷社区 | 色综合天天在线 | 国产一区二区三区高清播放 | 欧美成人精品欧美一级乱 | 最新国产中文字幕 | 欧美坐爱视频 | 日韩在线观看a | 国产一区二区久久精品 | 成人在线播放网站 | 91在线网址 | 国产视频在 | 婷婷丁香激情网 | 日韩一二区在线观看 | 激情久久一区二区三区 | 制服丝袜一区二区 | 开心激情婷婷 | 国产剧情在线一区 | 97碰在线视频 | 五月亚洲综合 | 国产最新精品视频 | 99在线观看 | 91精品国产99久久久久久久 | 国产精品乱码高清在线看 | 久久无码av一区二区三区电影网 | 四虎8848免费高清在线观看 | 国产 色 | 国产精彩视频一区二区 | 亚洲综合色丁香婷婷六月图片 | 国产视频一区二区三区在线 | 国产精品日韩欧美一区二区 | 国产麻豆剧果冻传媒视频播放量 | 国产视频久久久 | 国产午夜三级一区二区三桃花影视 | 欧美另类高清 videos | 视频在线91 | 日韩一级电影在线观看 |