android adb install apk的安装流程

目录:

          一、PackageManagerService启动流程

         二、apk adb安装流程

 

一、简介

     1.Android上应用安装可以分为以下几种方式:

  • 通过adb命令安装:adb 命令包括adb push/install
  • 用户下载的Apk,通过系统安装器packageinstaller安装该Apk。packageinstaller是系统内置的应用程序,用于安装和卸载应用程序。
  • 系统开机时安装系统应用。
  • 电脑或者手机上的应用商店自动安装

第三种系统安装我们在上个章节PackageManagerService启动流程已经说过,剩余的三种其实没什么太大的区别,主要的流程都是:1)PackageInstallerService.createSession创建sessionId。

      2) session = new PackageInstaller.Session( mInterface.getPackageInstaller().openSession(sessionId)),splitName=base.apk
            out = session.openWrite(splitName, 0, sizeBytes);创建一个临时的apk :/data/app/vmd+sessionId+tmp/base.apk ,把原apkt保存到刚刚创建的apk文件中

   3) PackageInstaller.Session.commit

他们的差别是:第一种是通过adb的方式安装,第二中是通过packageinstaller.apk的方式安装,第三种是oem厂商自己写,可以满足静默安装,默认赋予动态权限等。

 

2.APK文件结构:

目录/文件描述
assert存放的原生资源文件,通过AssetManager类访问。
lib存放库文件。
META-INF保存应用的签名信息,签名信息可以验证APK文件的完整性。
res存放资源文件。res中除了raw子目录,其他的子目录都参与编译,这些子目录下的资源是通过编译出的R类在代码中访问。
AndroidManifest.xml用来声明应用程序的包名称、版本、组件和权限等数据。 apk中的AndroidManifest.xml经过压缩,可以通过AXMLPrinter2工具解开。
classes.dexJava源码编译后生成的Java字节码文件。
resources.arsc编译后的二进制资源文件。

apk的安装主要会解析上面哪几个文件呢?assert,lib,META-INF,res,AndroidManifest.xml。至于classes.dex是在apk启动的时候加载的。

 

3.adb install 安装时序图

 上面图片不清晰的,可以查看https://download.csdn.net/download/Bill_xiao/12328139

 

二、adb 安装流程

  1.adb install +apk,这个命令会通过adb程序调用shell脚本,shell脚本会根据传递的参数来选择调用cmd程序,cmd在system/bin下面。

cmd.cpp的main函数会执行  status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,  cb, result);而它会调用PackageManagerServcie.onShellCommand方法

 public void onShellCommand(FileDescriptor in, FileDescriptor out,
            FileDescriptor err, String[] args, ShellCallback callback,
            ResultReceiver resultReceiver) {
  
        (new PackageManagerShellCommand(this)).exec(
                this, in, out, err, args, callback, resultReceiver);
    }

PackageManagerShellCommand 继承ShellCommand  ShellCommand.exec方法如下,可以看出会回调子类的onCommand方法

 public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
        String cmd;
		
        int start;
        if (args != null && args.length > 0) {
            cmd = args[0];
            start = 1;
        } else {
            cmd = null;
            start = 0;
        }
        init(target, in, out, err, args, callback, start);
		// Log.i(" PackageManagerService-xiao", "ShellCommand exec cmd:"+cmd);
        mCmd = cmd;
        mResultReceiver = resultReceiver;

        if (DEBUG) Log.i(TAG, "Starting command " + mCmd + " on " + mTarget);
        int res = -1;
        try {
            res = onCommand(mCmd);
            if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
        } catch (SecurityException e) {
            PrintWriter eout = getErrPrintWriter();
            eout.println("Security exception: " + e.getMessage());
            eout.println();
            e.printStackTrace(eout);
        } catch (Throwable e) {
            // Unlike usual calls, in this case if an exception gets thrown
            // back to us we want to print it back in to the dump data, since
            // that is where the caller expects all interesting information to
            // go.
            PrintWriter eout = getErrPrintWriter();
            eout.println();
            eout.println("Exception occurred while executing:");
            e.printStackTrace(eout);
        } finally {
            if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
            if (mOutPrintWriter != null) {
                mOutPrintWriter.flush();
            }
            if (mErrPrintWriter != null) {
                mErrPrintWriter.flush();
            }
            if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
            mResultReceiver.send(res, null);
        }
        if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
        return res;
    }
 @Override
    public int onCommand(String cmd) {
   
        if (cmd == null) {
            return handleDefaultCommands(cmd);
        }

        final PrintWriter pw = getOutPrintWriter();
        try {
            switch(cmd) {
                case "install":
                    return runInstall();
                case "install-abandon":
                case "install-destroy":
                    return runInstallAbandon();
                case "install-commit":
                    return runInstallCommit();
                case "install-create":
                    return runInstallCreate();
                case "install-remove":
                    return runInstallRemove();
                case "install-write":
                    return runInstallWrite();
                case "install-existing":
                    return runInstallExisting();
                case "compile":
                    return runCompile();
                case "reconcile-secondary-dex-files":
                    return runreconcileSecondaryDexFiles();
                case "bg-dexopt-job":
                    return runDexoptJob();
                case "dump-profiles":
                    return runDumpProfiles();
                case "list":
                    return runList();
                case "uninstall":
                    return runUninstall();
                case "resolve-activity":
                    return runResolveActivity();
                case "query-activities":
                    return runQueryIntentActivities();
                case "query-services":
                    return runQueryIntentServices();
                case "query-receivers":
                    return runQueryIntentReceivers();
                case "suspend":
                    return runSuspend(true);
                case "unsuspend":
                    return runSuspend(false);
                case "set-home-activity":
                    return runSetHomeActivity();
                case "get-privapp-permissions":
                    return runGetPrivappPermissions();
                case "get-privapp-deny-permissions":
                    return runGetPrivappDenyPermissions();
                case "get-instantapp-resolver":
                    return runGetInstantAppResolver();
                case "has-feature":
                    return runHasFeature();
                default:
                    return handleDefaultCommands(cmd);
            }
        } catch (RemoteException e) {
            pw.println("Remote exception: " + e);
        }
        return -1;
    }

从上面函数就能看出,不同的参数会执行不同的方法,我们的install,所以会执行runInstall()方法:

1.doCreateSession  :创建PackageInstaller.Session函数。

2.doWriteSplit  :创建一个临时的apk :/data/app/vmd+sessionId+tmp/base.apk

3.doCommitSession   :执行PackageInstaller.Session.commit方法,这一步才开始apk的安装。等待系统安装完成会发送一个广播带有PackageInstaller.EXTRA_STATUS字段的信息,里面回保存安装结果success或者Failure的原因

 private int runInstall() throws RemoteException {
   
        final PrintWriter pw = getOutPrintWriter();
        final InstallParams params = makeInstallParams();
        final String inPath = getNextArg();

        setParamsSize(params, inPath);
		 //创建sessionId    mSessions.put(sessionId, session);
        final int sessionId = doCreateSession(params.sessionParams,
                params.installerPackageName, params.userId);
		
	
        boolean abandonSession = true;
        try {
			
            if (inPath == null && params.sessionParams.sizeBytes == -1) {
                pw.println("Error: must either specify a package size or an APK file");
                return 1;
            }
			
			//创建一个临时的apk :/data/app/vmd+sessionId+tmp/base.apk ,把原apk保存到刚刚创建的apk文件中
            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                return 1;
            }
		
            if (doCommitSession(sessionId, false /*logSuccess*/)
                    != PackageInstaller.STATUS_SUCCESS) {
                return 1;
            }
            abandonSession = false;
            pw.println("Success");
            return 0;
        } finally {
            if (abandonSession) {
                try {
                    doAbandonSession(sessionId, false /*logSuccess*/);
                } catch (Exception ignore) {
                }
            }
        }
    }

我们来看看sessionId到底是什么?

如下代码可以得出:

                             1.会检查用户是否具有安装apk的权限,添加一些安装flag

                             2.随机产生一个sessionId值,创建stageDir目录:/data/app/vmd+sessionId+tmp

                             3.创建一个新的session,并且 保存值到mSessions,mSessions.put(sessionId, session);

PackageInstallerService.createSession

 public int createSession(SessionParams params, String installerPackageName, int userId) {
        try {
            return createSessionInternal(params, installerPackageName, userId);
        } catch (IOException e) {
            throw ExceptionUtils.wrap(e);
        }
    }

    private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
            throws IOException {
        final int callingUid = Binder.getCallingUid();
		
        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");//检查APK安装权限
         //检查用户权限
        if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
            throw new SecurityException("User restriction prevents installing");
        }
          //如果是root权限或者shell脚本安装(adb 安装)的赋值INSTALL_FROM_ADB
        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
            params.installFlags |= PackageManager.INSTALL_FROM_ADB;

        } else {
            mAppOps.checkPackage(callingUid, installerPackageName);//检查包名跟uid是否匹配

            params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
            params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
            params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
                    && !mPm.isCallerVerifier(callingUid)) {
                params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
            }
        }

        // Only system components can circumvent runtime permissions when installing.
        //检查运行权限 adb安装就没有这个检查
        if ((params.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 ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
                || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
            throw new IllegalArgumentException(
                    "New installs into ASEC containers no longer supported");
        }
    
			
        // Defensively resize giant app icons
      
        if (params.appIcon != null) {
            final ActivityManager am = (ActivityManager) mContext.getSystemService(
                    Context.ACTIVITY_SERVICE);
            final int iconSize = am.getLauncherLargeIconSize();
            if ((params.appIcon.getWidth() > iconSize * 2)
                    || (params.appIcon.getHeight() > iconSize * 2)) {
                params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
                        true);
            }
        }

        switch (params.mode) {
            case SessionParams.MODE_FULL_INSTALL:
            case SessionParams.MODE_INHERIT_EXISTING:
                break;
            default:
                throw new IllegalArgumentException("Invalid install mode: " + params.mode);
        }

        // If caller requested explicit location, sanity check it, otherwise
        // resolve the best internal or adopted location.
        //检测apk需要安装到指定文件夹挂载情况,/data/app
        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
            if (!PackageHelper.fitsOnInternal(mContext, params)) {
                throw new IOException("No suitable internal storage available");
            }

        } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
            if (!PackageHelper.fitsOnExternal(mContext, params)) {
                throw new IOException("No suitable external storage available");
            }

        } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
            // For now, installs to adopted media are treated as internal from
            // an install flag point-of-view.
            params.setInstallFlagsInternal();

        } else {
            // For now, installs to adopted media are treated as internal from
            // an install flag point-of-view.
            
            params.setInstallFlagsInternal();

            // Resolve best location for install, based on combination of
            // requested install flags, delta size, and manifest settings.
            final long ident = Binder.clearCallingIdentity();
            try {
                params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

        final int sessionId;
        final PackageInstallerSession session;
        synchronized (mSessions) {
            // Sanity check that installer isn't going crazy
            //表示由callingUid进程所执行安装的apk有多少个
            final int activeCount = getSessionCount(mSessions, callingUid);
            if (activeCount >= MAX_ACTIVE_SESSIONS) {
                throw new IllegalStateException(
                        "Too many active sessions for UID " + callingUid);
            }
			//表示由callingUid进程所已经安装的apk有多少个
            final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
            if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
                throw new IllegalStateException(
                        "Too many historical sessions for UID " + callingUid);
            }
               //随机产生一个数字,并且放到mAllocatedSessions
            sessionId = allocateSessionIdLocked();
			
		


        final long createdMillis = System.currentTimeMillis();
        // We're staging to exactly one location
        File stageDir = null;
        String stageCid = null;
        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
            final boolean isInstant =
                    (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
			//params.volumeUuid=null  stageDir:/data/app/vmd+sessionId+tmp
            stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
        } else {
            stageCid = buildExternalStageCid(sessionId);//"smdl" + sessionId + ".tmp";
        }


        session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
                mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
                params, createdMillis, stageDir, stageCid, false, false);

        synchronized (mSessions) {
            mSessions.put(sessionId, session);
        }

        mCallbacks.notifySessionCreated(session.sessionId, session.userId);//通知回调session创建成功
        writeSessionsAsync();
        return sessionId;
    }

doWriteSplit比较简单,可以自行研究。那我们来看看doCommitSession  的PackageInstaller.Session.commit做了哪些东西?

  public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
        Preconditions.checkNotNull(statusReceiver);
		
        final boolean wasSealed;
        synchronized (mLock) {
            assertCallerIsOwnerOrRootLocked();
            assertPreparedAndNotDestroyedLocked("commit");

            final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
                    mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
			//获取IPackageInstallObserver2.Stub
            mRemoteObserver = adapter.getBinder();

            if (forTransfer) {
                mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);

                if (mInstallerUid == mOriginalInstallerUid) {
                    throw new IllegalArgumentException("Session has not been transferred");
                }
            } else {
            //uid检查
                if (mInstallerUid != mOriginalInstallerUid) {
                    throw new IllegalArgumentException("Session has been transferred");
                }
            }
			//没有调用sealAndValidateLocked之前都是false

            wasSealed = mSealed;
            if (!mSealed) {
                try {
                    sealAndValidateLocked();
                } catch (IOException e) {
                    throw new IllegalArgumentException(e);
                } catch (PackageManagerException e) {
                    destroyInternal();

                    // Cannot call dispatchFinal synchronous as this might be called from inside the
                    // system server on the main thread. Hence the call back scheduled in
                    // dispachFinal has to be scheduled on a different thread.
                    mHandler.obtainMessage(MSG_SESSION_FINISHED_WITH_EXCEPTION, e).sendToTarget();

                    return;
                }
            }

            // Client staging is fully done at this point
            mClientProgress = 1f;
            computeProgressLocked(true);

            // This ongoing commit should keep session active, even though client
            // will probably close their end.
            mActiveCount.incrementAndGet();

            mCommitted = true;
            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
        }

        if (!wasSealed) {
            // Persist the fact that we've sealed ourselves to prevent
            // mutations of any hard links we create. We do this without holding
            // the session lock, since otherwise it's a lock inversion.
            mCallback.onSessionSealedBlocking(this);
        }
    }

主要做了:1.创建PackageInstallObserverAdapter实例,从名字就能知道是用于apk的安装结果观察。

                  2.调用sealAndValidateLocked()方法

                  3.发送MSG_COMMIT广播。

先重点查看sealAndValidateLocked做了什么事

 private void sealAndValidateLocked() throws PackageManagerException, IOException {
        assertNoWriteFileTransfersOpenLocked();
        assertPreparedAndNotDestroyedLocked("sealing of session");
         //如果此apk已经安装过,或者存在的话,从mPackages中获取packageInfo,如果没有就是null
        final PackageInfo pkgInfo = mPm.getPackageInfo(
                params.appPackageName, PackageManager.GET_SIGNATURES
                        | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);

      File mFile= resolveStageDirLocked();

        mSealed = true;

        // Verify that stage looks sane with respect to existing application.
        // This currently only ensures packageName, versionCode, and certificate
        // consistency.
        try {
            validateInstallLocked(pkgInfo);
        } catch (PackageManagerException e) {
            throw e;
        } catch (Throwable e) {
            // Convert all exceptions into package manager exceptions as only those are handled
            // in the code above
            throw new PackageManagerException(e);
        }

        // Read transfers from the original owner stay open, but as the session's data
        // cannot be modified anymore, there is no leak of information.
    }

 从上述的代码看:1.查询此apk是否安装过,如果安装过的话pkgInfo不为空

                             2.resolveStageDirLocked 获取apk源文件目录,这个目录是在createSession中创建的:/data/app/vmd+sessionId+tmp

                             3.执行validateInstallLocked方法,扫描/data/app/vmd+sessionId+tmp 目录下的文件,清空缓存文件,对以.apk结尾的文件进行扫描。获取一些基本的apk信息,主要解析mainfest,获取包名及其他属性信息coreApp ,multiArch, use32bitAbi,extractNativeLibs ,versionCode 。

  private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
            throws PackageManagerException {
        mPackageName = null;
        mVersionCode = -1;
        mSignatures = null;

        mResolvedBaseFile = null;
        mResolvedStagedFiles.clear();
        mResolvedInheritedFiles.clear();

        try {
            resolveStageDirLocked();
        } catch (IOException e) {
            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
                    "Failed to resolve stage location", e);
        }
    
     //移除/data/app/vmd+sessionId+tmp下面.removed结尾的文件
		final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
        final List<String> removeSplitList = new ArrayList<>();
        if (!ArrayUtils.isEmpty(removedFiles)) {
            for (File removedFile : removedFiles) {
                final String fileName = removedFile.getName();
                final String splitName = fileName.substring(
                        0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
                removeSplitList.add(splitName);
            }
        }
		//添加/data/app/vmd+lsessionId+tmp下面,不是.removed结尾的文件

        final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
        if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
        }
        // Verify that all staged packages are internally consistent
        final ArraySet<String> stagedSplits = new ArraySet<>();
        for (File addedFile : addedFiles) {
            final ApkLite apk;
            try {
				 
                int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
                if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
                    flags |= PackageParser.PARSE_IS_EPHEMERAL;
                }
//解析apk,主要解析mainfest,获取包名及其他属性信息coreApp ,multiArch,             use32bitAbi, extractNativeLibs ,versionCode 
                apk = PackageParser.parseApkLite(addedFile, flags);
				
            } catch (PackageParserException e) {
                throw PackageManagerException.from(e);
            }

            if (!stagedSplits.add(apk.splitName)) {
                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                        "Split " + apk.splitName + " was defined multiple times");
            }

            // Use first package to define unknown values
            
            if (mPackageName == null) {
                mPackageName = apk.packageName;
                mVersionCode = apk.versionCode;
            }
            if (mSignatures == null) {
                mSignatures = apk.signatures;
                mCertificates = apk.certificates;
            }

            assertApkConsistentLocked(String.valueOf(addedFile), apk);

            // Take this opportunity to enforce uniform naming
            final String targetName;
            if (apk.splitName == null) {
                targetName = "base.apk";
            } else {
                targetName = "split_" + apk.splitName + ".apk";
            }
            if (!FileUtils.isValidExtFilename(targetName)) {
                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                        "Invalid filename: " + targetName);
            }
			

            final File targetFile = new File(mResolvedStageDir, targetName);
            if (!addedFile.equals(targetFile)) {
                addedFile.renameTo(targetFile);
            }

            // Base is coming from session
            if (apk.splitName == null) {
                mResolvedBaseFile = targetFile;
            }

            mResolvedStagedFiles.add(targetFile);
        }

        if (removeSplitList.size() > 0) {
            if (pkgInfo == null) {
                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                        "Missing existing base package for " + mPackageName);
            }

            // validate split names marked for removal
            for (String splitName : removeSplitList) {
                if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                            "Split not found: " + splitName);
                }
            }

            // ensure we've got appropriate package name, version code and signatures
            if (mPackageName == null) {
                mPackageName = pkgInfo.packageName;
                mVersionCode = pkgInfo.versionCode;
            }
            if (mSignatures == null) {
                mSignatures = pkgInfo.signatures;
            }
        }
	
      //PackageManagerShellCommand makeInstallParams 在初始化就赋值SessionParams.MODE_FULL_INSTALL
        if (params.mode == SessionParams.MODE_FULL_INSTALL) {
            // Full installs must include a base package
            if (!stagedSplits.contains(null)) {
                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                        "Full install must include a base package");
            }

        } else {
            // Partial installs must be consistent with existing install
            if (pkgInfo == null || pkgInfo.applicationInfo == null) {
                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                        "Missing existing base package for " + mPackageName);
            }

            final PackageLite existing;
            final ApkLite existingBase;
            ApplicationInfo appInfo = pkgInfo.applicationInfo;
            try {
                existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
                        PackageParser.PARSE_COLLECT_CERTIFICATES);
            } catch (PackageParserException e) {
                throw PackageManagerException.from(e);
            }

            assertApkConsistentLocked("Existing base", existingBase);//包名版本的信息检测

            // Inherit base if not overridden
            if (mResolvedBaseFile == null) {
                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                mResolvedInheritedFiles.add(mResolvedBaseFile);
            }

            // Inherit splits if not overridden
            if (!ArrayUtils.isEmpty(existing.splitNames)) {
                for (int i = 0; i < existing.splitNames.length; i++) {
                    final String splitName = existing.splitNames[i];
Log.i(" PackageManagerService-xiao", "PackageInstallerSession validateInstallLocked splitName :"+splitName);			
                    final File splitFile = new File(existing.splitCodePaths[i]);
                    final boolean splitRemoved = removeSplitList.contains(splitName);
                    if (!stagedSplits.contains(splitName) && !splitRemoved) {
                        mResolvedInheritedFiles.add(splitFile);
                    }
                }
            }

            // Inherit compiled oat directory.
            final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
            mInheritedFilesBase = packageInstallDir;
            final File oatDir = new File(packageInstallDir, "oat");
			//解析odx
            if (oatDir.exists()) {
                final File[] archSubdirs = oatDir.listFiles();

                // Keep track of all instruction sets we've seen compiled output for.
                // If we're linking (and not copying) inherited files, we can recreate the
                // instruction set hierarchy and link compiled output.
                if (archSubdirs != null && archSubdirs.length > 0) {
                    final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
                    for (File archSubDir : archSubdirs) {
                        // Skip any directory that isn't an ISA subdir.
                        if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
                            continue;
                        }

                        mResolvedInstructionSets.add(archSubDir.getName());
                        List<File> oatFiles = Arrays.asList(archSubDir.listFiles());

                        // Only add compiled files associated with the base.
                        // Once b/62269291 is resolved, we can add all compiled files again.
                        for (File oatFile : oatFiles) {
                            if (oatFile.getName().equals("base.art")
                                    || oatFile.getName().equals("base.odex")
                                    || oatFile.getName().equals("base.vdex")) {
                                mResolvedInheritedFiles.add(oatFile);
                            }
                        }
                    }
                }
            }
        }
    }

现在我们来看看MSG_COMMIT做什么?就是直接调用commitLocked

 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_COMMIT:
                    synchronized (mLock) {
                        try {
                            commitLocked();
                        } catch (PackageManagerException e) {
                            final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                            Slog.e(TAG,
                                    "Commit of session " + sessionId + " failed: " + completeMsg);
                            destroyInternal();
                            dispatchSessionFinished(e.error, completeMsg, null);
                        }
                    }
private void commitLocked()
            throws PackageManagerException {
        if (mDestroyed) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
        }
        if (!mSealed) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
        }

        Preconditions.checkNotNull(mPackageName);
        Preconditions.checkNotNull(mSignatures);
        Preconditions.checkNotNull(mResolvedBaseFile);

    //needToAskForPermissionsLocked  是否具有静默安装权限
        if (needToAskForPermissionsLocked()) {
            // User needs to accept permissions; give installer an intent they
            // can use to involve user.
            //发送广播权限已经被确认好了
            final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
            intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
            intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
            try {
                mRemoteObserver.onUserActionRequired(intent);
            } catch (RemoteException ignored) {
            }

            // Commit was keeping session marked as active until now; release
            // that extra refcount so session appears idle.
            closeInternal(false);
            return;
        }

        if (stageCid != null) {
            // Figure out the final installed size and resize the container once
            // and for all. Internally the parser handles straddling between two
            // locations when inheriting.
            final long finalSize = calculateInstalledSize();
            resizeContainer(stageCid, finalSize);
        }

        // Inherit any packages and native libraries from existing install that
        // haven't been overridden.
        if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
            try {
                final List<File> fromFiles = mResolvedInheritedFiles;
                final File toDir = resolveStageDirLocked();

                if (LOGD) Log.d("PackageManagerService-xiao", "Inherited files: " + mResolvedInheritedFiles);
                if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
                    throw new IllegalStateException("mInheritedFilesBase == null");
                }

                if (isLinkPossible(fromFiles, toDir)) {
                    if (!mResolvedInstructionSets.isEmpty()) {
                        final File oatDir = new File(toDir, "oat");
                        createOatDirs(mResolvedInstructionSets, oatDir);
                    }
                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
                } else {
                    // TODO: this should delegate to DCS so the system process
                    // avoids holding open FDs into containers.
                    copyFiles(fromFiles, toDir);
                }
            } catch (IOException e) {
                throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                        "Failed to inherit existing install", e);
            }
        }

        // TODO: surface more granular state from dexopt
        mInternalProgress = 0.5f;
        computeProgressLocked(true);

        // Unpack native libraries

        extractNativeLibraries(mResolvedStageDir, params.abiOverride);//拷贝外部的库

        // Container is ready to go, let's seal it up!
        if (stageCid != null) {
            finalizeAndFixContainer(stageCid);
        }

        // We've reached point of no return; call into PMS to install the stage.
        // Regardless of success or failure we always destroy session.
        final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
            @Override
            public void onUserActionRequired(Intent intent) {
                throw new IllegalStateException();
            }

            @Override
            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                    Bundle extras) {
                destroyInternal();//删除stageDir临时文件
                dispatchSessionFinished(returnCode, msg, extras);
            }
        };

        final UserHandle user;
        if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
            user = UserHandle.ALL;
        } else {
            user = new UserHandle(userId);
        }

        mRelinquished = true;
        mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
                mInstallerPackageName, mInstallerUid, user, mCertificates);
    }

确认安装权限和安装位置之后调用PackageManagerService.installStage。大家有没有一种恍然大悟的感觉,之前所做的所有事情最后都是会回到PackageManagerService,由它来扫描安装apk。那之后的过程跟我们之前讲述的系统扫描是否会相同呢?

void installStage(String packageName, File stagedDir, String stagedCid,
            IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
            String installerPackageName, int installerUid, UserHandle user,
            Certificate[][] certificates) {
     
        if (true) {
            if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
                Log.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);
    }

创建安装参数InstallParams,发送安装广播INIT_COPY。

 void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
	//  idx为当前需要安装的APK个数,mPendingInstalls里面保存所有需要安装的APK解析出来的HandlerParams参数
                    int idx = mPendingInstalls.size();
                    if (DEBUG_INSTALL) Log.i(TAG, "doHandleMessage init_copy idx=" + idx + ": " + params);
                    // If a bind was already initiated we dont really
                    // need to do anything. The pending install
                    // will be processed later on.
                    if (!mBound) {
                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                System.identityHashCode(mHandler));
                        // If this is the only one pending we might
                        // have to bind to the service again.
		              /*
		               APK的安装居然需要使用另外一个APK提供的服务,该服务就是
		             DefaultContainerService,由DefaultCotainerService.apk提供,
		             下面的connectToService函数将调用bindService来启动该服务
		              */
                        if (!connectToService()) {
                            Log.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                    System.identityHashCode(mHandler));
                            if (params.traceMethod != null) {
                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
                                        params.traceCookie);
                            }
                            return;
                        } else {//服务启动完
                            // Once we bind to the service, the first
                            // pending request will be processed.
                            
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                        mPendingInstalls.add(idx, params);
                        // Already bound to the service. Just make
                        // sure we trigger off processing the first request.
                        //启动安装
                        if (idx == 0) {
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                    break;
                }
                case MCS_BOUND: {
                    if (DEBUG_INSTALL) Log.i(TAG, "mcs_bound");
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                System.identityHashCode(mHandler));
                    }
                    if (mContainerService == null) {
                        if (!mBound) {
                            // Something seriously wrong since we are not bound and we are not
                            // waiting for connection. Bail out.
                            Log.e(TAG, "Cannot bind to media container service");
                            for (HandlerParams params : mPendingInstalls) {
                                // Indicate service bind error
                                params.serviceError();
                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                        System.identityHashCode(params));
                                if (params.traceMethod != null) {
                                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
                                            params.traceMethod, params.traceCookie);
                                }
                                return;
                            }
                            mPendingInstalls.clear();//如果没法启动该service,则不能安装程序
                        } else {
                            Log.w(TAG, "Waiting to connect to media container service");
                        }
                    } else if (mPendingInstalls.size() > 0) {
                        HandlerParams params = mPendingInstalls.get(0);
                        if (params != null) {
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                    System.identityHashCode(params));
                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                            if (params.startCopy()) {
                                // We are done...  look for more work or to
                                // go idle.
                                if (DEBUG_SD_INSTALL) Log.i(TAG,
                                        "Checking for more work or unbind...");
                                // Delete pending install
                                if (mPendingInstalls.size() > 0) {
                                    mPendingInstalls.remove(0);//删除队列头
                                }
                                if (mPendingInstalls.size() == 0) {
                                    if (mBound) {
                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
                                                "Posting delayed MCS_UNBIND");
										//如果安装请求都处理完了,则需要和Service断绝联系,
                                //通过发送MSC_UNB消息处理断交请求。
                                        removeMessages(MCS_UNBIND);
                                        Message ubmsg = obtainMessage(MCS_UNBIND);
                                        // Unbind after a little delay, to avoid
                                        // continual thrashing.
                                        sendMessageDelayed(ubmsg, 10000);
                                    }
                                } else {
                                    // There are more pending requests in queue.
                                    // Just post MCS_BOUND message to trigger processing
                                    // of next pending install.
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Posting MCS_BOUND for next work");
                                    mHandler.sendEmptyMessage(MCS_BOUND);
                                }
                            }
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }
                    } else {
                        // Should never happen ideally.
                        Log.w(TAG, "Empty queue");
                    }
                    break;
                }

doHandleMessage 处理INIT_COPY广播主要做了哪些事情。

  1.连接DefaultCotainerService服务,把刚才send的信息添加到 mPendingInstalls.add(idx, params)。发送mHandler.sendEmptyMessage(MCS_BOUND)广播。

2.执行params.startCopy(),params就是之前InstallParams。

 HandlerParams和InstallArgs介绍

除了HandlerParams家族外,这里提前请出另外一个家族InstallArgs及其成员,如图4-8所示。
:-: 
图4-8 HandlerParams及InstallArgs家族成员

由图4-8可知:

  • HandlerParams和InstallArgs均为抽象类。
  • HandlerParams有三个子类,分别是InstallParams、MoveParams和MeasureParams。其中,InstallParams用于处理APK的安装,MoveParams用于处理某个已安装APK的搬家请求(例如从内部存储移动到SD卡上),MeasureParams用于查询某个已安装的APK占据存储空间的大小(例如在设置程序中得到的某个APK使用的缓存文件的大小)。
  • 对于InstallParams来说,它还有两个伴儿,即InstallArgs的派生类FileInstallArgs和SdInstallArgs。其中,FileInstallArgs针对的是安装在内部存储的APK,而SdInstallArgs针对的是那些安装在SD卡上的APK。

 

  final boolean startCopy() {
            boolean res;
            try {
                if (DEBUG_INSTALL) Log.i(TAG, "HandlerParams startCopy " + mUser + ": " + this);
				//MAX_RETIRES目前为4,表示尝试4次安装,如果还不成功,则认为安装失败
                if (++mRetries > MAX_RETRIES) {
                    Log.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);
                    handleServiceError();
                    return false;
                } else {
                    handleStartCopy();
                    res = true;
                }
            } catch (RemoteException e) {
                if (DEBUG_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");
                mHandler.sendEmptyMessage(MCS_RECONNECT);
                res = false;
            }
            handleReturnCode();
            return res;
        }

在上述代码中,基类的startCopy将调用子类实现的handleStartCopy和handleReturnCode函数。下面来看InstallParams是如何实现这两个函数的。先来看派生类InstallParams的handleStartCopy函数

  public void handleStartCopy() throws RemoteException {
            int ret = PackageManager.INSTALL_SUCCEEDED;
			Log.i(" PackageManagerService-xiao", "PackageManagerService handleStartCopy origin.staged:"+origin.staged);

            // If we're already staged, we've firmly committed to an install location
            // 是安装在手机内部存储空间还是sdcard中,设置对应标志位
            // 新安装的情况下stage为true,也就是默认内部存储
            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");
                }
            }

            final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;//安装到sd卡
            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;//安装到内部存储
            final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
            PackageInfoLite pkgLite = null;
           // 检查APK的安装位置是否正确
            if (onInt && onSd) {//不能同时安装到内部和外部
                // Check if both bits are set.
                Log.w(TAG, "Conflicting flags specified for installing on both internal and external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else if (onSd && ephemeral) {
                Log.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else {//一般是这个
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                        packageAbiOverride);//获取一个合适的安装位置,包名等

                if (DEBUG_EPHEMERAL && ephemeral) {
                    Log.v(TAG, "pkgLite for install: " + pkgLite);
                }

                /*
                 * If we have too little free space, try to free cache
                 * before giving up.
                 */
                 
                if (!origin.staged && pkgLite.recommendedInstallLocation
                        == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    // TODO: focus freeing disk space on the target device
                    final StorageManager storage = StorageManager.from(mContext);
					//从DSMS查询内部空间最小余量,默认是总空间的10%
                    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) {
                        Log.w(TAG, "Failed to free cache", e);
                    }

                    /*
                     * The cache free must have deleted the file we
                     * downloaded to install.
                     *
                     * TODO: fix the "freeCache" call to not delete
                     *       the file we care about.
                     */
                    if (pkgLite.recommendedInstallLocation
                            == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                        pkgLite.recommendedInstallLocation
                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                    }
                }
            }
             
            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                int loc = pkgLite.recommendedInstallLocation;
                if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                    ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                    ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                } else {
                    /// M: Removable system app support
                    installFlags = sPmsExt.customizeInstallPkgFlags(installFlags, pkgLite,
                            mSettings.mPackages, getUser());
                    // Override with defaults if needed.
                    //②根据DCS返回的安装路径,还需要调用installLocationPolicy进行检查
                    loc = installLocationPolicy(pkgLite);
                    if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                        ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
                    } else if (!onSd && !onInt) {
                        // Override install location with flags
                        if (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) {
                                Log.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 unset
                            installFlags |= PackageManager.INSTALL_INTERNAL;
                            installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                        }
                    }
                }
            }
     //③创建一个安装参数对象,对于安装位置为内部存储的情况,args的真实类型为FileInstallArgs
            final InstallArgs args = createInstallArgs(this);
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                // TODO: http://b/22976637
                // Apps installed for "all" users use the device owner to verify the app
                UserHandle verifierUser = getUser();
                if (verifierUser == UserHandle.ALL) {
                    verifierUser = UserHandle.SYSTEM;
                }

                /*
                 * Determine if we have any installed package verifiers. If we
                 * do, then we'll defer to them to verify the packages.
                 */
                final int requiredUid = mRequiredVerifierPackage == null ? -1
                        : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
                                verifierUser.getIdentifier());
                final int installerUid =
                        verificationInfo == null ? -1 : verificationInfo.installerUid;
                if (!origin.existing && requiredUid != -1
                        && isVerificationEnabled(
                                verifierUser.getIdentifier(), installFlags, installerUid)) {
                                // 对当前包做验证操作
                    final Intent verification = new Intent(
                            Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                    verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                    verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                            PACKAGE_MIME_TYPE);
                    verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                    // Query all live verifiers based on current user state
                    final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
                            PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
                            false /*allowDynamicSplits*/);

                    if (DEBUG_VERIFY) {
                        Log.d(TAG, "Found " + receivers.size() + " verifiers for intent "
                                + verification.toString() + " with " + pkgLite.verifiers.length
                                + " optional verifiers");
                    }

                    final int verificationId = mPendingVerificationToken++;

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
                            installerPackageName);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
                            installFlags);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
                            pkgLite.packageName);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
                            pkgLite.versionCode);

                    if (verificationInfo != null) {
                        if (verificationInfo.originatingUri != null) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
                                    verificationInfo.originatingUri);
                        }
                        if (verificationInfo.referrer != null) {
                            verification.putExtra(Intent.EXTRA_REFERRER,
                                    verificationInfo.referrer);
                        }
                        if (verificationInfo.originatingUid >= 0) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
                                    verificationInfo.originatingUid);
                        }
                        if (verificationInfo.installerUid >= 0) {
                            verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
                                    verificationInfo.installerUid);
                        }
                    }

                    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) {
                            Log.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");

                                final Intent sufficientIntent = new Intent(verification);
                                sufficientIntent.setComponent(verifierComponent);
                                mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
                            }
                        }
                    }

                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
                            mRequiredVerifierPackage, receivers);
                    if (ret == PackageManager.INSTALL_SUCCEEDED
                            && mRequiredVerifierPackage != null) {
                        Trace.asyncTraceBegin(
                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
                        /*
                         * Send the intent to the required verification agent,
                         * but only start the verification timeout after the
                         * target BroadcastReceivers have run.
                         */
                        verification.setComponent(requiredVerifierComponent);
                        idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                mRequiredVerifierPackage, idleDuration,
                                verifierUser.getIdentifier(), false, "package verifier");
                        mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                                new BroadcastReceiver() {
                                    @Override
                                    public void onReceive(Context context, Intent intent) {
                                        final Message msg = mHandler
                                                .obtainMessage(CHECK_PENDING_VERIFICATION);
                                        msg.arg1 = verificationId;
                                        mHandler.sendMessageDelayed(msg, getVerificationTimeout());
                                    }
                                }, null, 0, null, null);

                        /*
                         * We don't want the copy to proceed until verification
                         * succeeds, so null out this field.
                         */
                        mArgs = null;
                    }
                } else {
                    /*
                     * No package verification is enabled, so immediately start
                     * the remote call to initiate copy using temporary file.
                     */
                     //调用args的copyApk函数
                    ret = args.copyApk(mContainerService, true);
                }
            }

            mRet = ret;
        }

在以上代码中,一共列出了五个关键点,总结如下:

  • 调用DCS的getMinimalPackageInfo函数,将得到一个PackageLite对象,该对象是一个轻量级的用于描述APK的结构(相比PackageParser.Package来说)。在这段代码逻辑中,主要想取得其recommendedInstallLocation的值。此值表示该APK推荐的安装路径。
  • 调用installLocationPolicy检查推荐的安装路径。例如系统Package不允许安装在SD卡上。
  • createInstallArgs将根据安装位置创建不同的InstallArgs。如果是内部存储,则返回FileInstallArgs,否则为SdInstallArgs。
  • 在正式安装前,应先对该APK进行必要的检查。这部分代码后续再介绍。
  • 调用InstallArgs的copyApk。对本例来说,将调用FileInstallArgs的copyApk函数。

 

DefaultContainerService.java::getMinimalPackageInfo函数

   public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
                String abiOverride) {
          
            final Context context = DefaultContainerService.this;
            final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;

            PackageInfoLite ret = new PackageInfoLite();
            if (packagePath == null) {
                Slog.i(TAG, "Invalid package file " + packagePath);
                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
                return ret;
            }

            final File packageFile = new File(packagePath);
            final PackageParser.PackageLite pkg;
            final long sizeBytes;
            try {
                pkg = PackageParser.parsePackageLite(packageFile, 0);
                sizeBytes = PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
            } catch (PackageParserException | IOException e) {
                Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);

                if (!packageFile.exists()) {
                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
                } else {
                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
                }

                return ret;
            }
          
            final int recommendedInstallLocation;
            final long token = Binder.clearCallingIdentity();
            try {
				//调用recommendAppInstallLocation,取得一个合理的安装位置PackageHelper.RECOMMEND_INSTALL_INTERNAL 或者RECOMMEND_INSTALL_EXTERNAL
                recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
                        pkg.packageName, pkg.installLocation, sizeBytes, flags);
            } finally {
                Binder.restoreCallingIdentity(token);
            }

            ret.packageName = pkg.packageName;
            ret.splitNames = pkg.splitNames;
            ret.versionCode = pkg.versionCode;
            ret.baseRevisionCode = pkg.baseRevisionCode;
            ret.splitRevisionCodes = pkg.splitRevisionCodes;
            ret.installLocation = pkg.installLocation;
            ret.verifiers = pkg.verifiers;
            ret.recommendedInstallLocation = recommendedInstallLocation;
            ret.multiArch = pkg.multiArch;

            return ret;
        }

        @Override
        public ObbInfo getObbInfo(String filename) {
            try {
                return ObbScanner.getObbInfo(filename);
            } catch (IOException e) {
                Slog.d(TAG, "Couldn't get OBB info for " + filename);
                return null;
            }
        }

APK可在AndroidManifest.xml中声明一个安装位置,不过DCS除了解析该位置外,还需要做进一步检查,这个工作由recommendAppInstallLocation函数完成,代码如下

 @Deprecated
    public static int resolveInstallLocation(Context context, String packageName,
            int installLocation, long sizeBytes, int installFlags) {
        final SessionParams params = new SessionParams(SessionParams.MODE_INVALID);
        params.appPackageName = packageName;
        params.installLocation = installLocation;
        params.sizeBytes = sizeBytes;
        params.installFlags = installFlags;
        try {
            return resolveInstallLocation(context, params);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }
public static int resolveInstallLocation(Context context, SessionParams params)
            throws IOException {
        ApplicationInfo existingInfo = null;
        try {
            existingInfo = context.getPackageManager().getApplicationInfo(params.appPackageName,
                    PackageManager.MATCH_ANY_USER);
        } catch (NameNotFoundException ignored) {
        }

        final int prefer;
        final boolean checkBoth;
        boolean ephemeral = false;
        if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
            prefer = RECOMMEND_INSTALL_INTERNAL;
            ephemeral = true;
            checkBoth = false;
        } else if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
            prefer = RECOMMEND_INSTALL_INTERNAL;
            checkBoth = false;
        } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
            prefer = RECOMMEND_INSTALL_EXTERNAL;
            checkBoth = false;
        } else if (params.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
            prefer = RECOMMEND_INSTALL_INTERNAL;
            checkBoth = false;
        } else if (params.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
            prefer = RECOMMEND_INSTALL_EXTERNAL;
            checkBoth = true;
        } else if (params.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {//一般设定的位置为AUTO,默认是内部空间
            // When app is already installed, prefer same medium
            if (existingInfo != null) {
                // TODO: distinguish if this is external ASEC
                if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                    prefer = RECOMMEND_INSTALL_EXTERNAL;
                } else {
                    prefer = RECOMMEND_INSTALL_INTERNAL;
                }
            } else {
                prefer = RECOMMEND_INSTALL_INTERNAL;
            }
            checkBoth = true;
        } else {
            prefer = RECOMMEND_INSTALL_INTERNAL;
            checkBoth = false;
        }

        boolean fitsOnInternal = false;
        if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
            fitsOnInternal = fitsOnInternal(context, params);
        }

        boolean fitsOnExternal = false;
        if (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) {
            fitsOnExternal = fitsOnExternal(context, params);
        }

        if (prefer == RECOMMEND_INSTALL_INTERNAL) {
            // The ephemeral case will either fit and return EPHEMERAL, or will not fit
            // and will fall through to return INSUFFICIENT_STORAGE
            if (fitsOnInternal) {
                return (ephemeral)
                        ? PackageHelper.RECOMMEND_INSTALL_EPHEMERAL
                        : PackageHelper.RECOMMEND_INSTALL_INTERNAL;
            }
        } else if (prefer == RECOMMEND_INSTALL_EXTERNAL) {
            if (fitsOnExternal) {
                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            }
        }

        if (checkBoth) {
            if (fitsOnInternal) {
                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
            } else if (fitsOnExternal) {
                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            }
        }

        return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
    }

DCS的getMinimalPackageInfo函数为了得到一个推荐的安装路径做了不少工作,其中,各种安装策略交叉影响。这里总结一下相关的知识点:

  • APK在AndroidManifest.xml中设置的安装点默认为AUTO,在具体对应时倾向内部空间。
  • 用户在Settings数据库中设置的安装位置。
  • 检查外部存储或内部存储是否有足够空间

PackageManagerService.java::InstallArgs.copyApk函数 

 int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
			
            try {
                return doCopyApk(imcs, temp);
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }
 /*
	    本例中temp参数为true,createCopyFile将在/data/app下创建一个临时文件。
	    临时文件名为vmdl-随机数.tmp。为什么会用这样的文件名呢?
	    因为PKMS通过Linux的inotify机制监控了/data/app,目录,如果新复制生成的文件名后缀
	    为apk,将触发PKMS扫描。为了防止发生这种情况,这里复制生成的文件才有了
	    如此奇怪的
	   */
	   //文件以及拷贝完成就不需要再拷贝
            if (origin.staged) {
                if (DEBUG_INSTALL) Log.d(TAG, origin.file + " already staged; skipping copy  temp:"+temp);
                codeFile = origin.file;
                resourceFile = origin.file;
                return PackageManager.INSTALL_SUCCEEDED;
            }

            try {
                final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
				// 创建目录 /data/app/vmdl1054430479.tmp/
                final File tempDir =
                        mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
			Log.i("PackageManagerService-xiao", "PackageManagerService FileInstallArgs tempDir:"+tempDir.getAbsolutePath());
                codeFile = tempDir;
                resourceFile = tempDir;
            } catch (IOException e) {
                Log.w(TAG, "Failed to create copy file: " + e);
                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }

            final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
                @Override
                public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
                    if (!FileUtils.isValidExtFilename(name)) {
                        throw new IllegalArgumentException("Invalid filename: " + name);
                    }
                    try {
                        final File file = new File(codeFile, name);
                        final FileDescriptor fd = Os.open(file.getAbsolutePath(),
                                O_RDWR | O_CREAT, 0644);
                        Os.chmod(file.getAbsolutePath(), 0644);
                        return new ParcelFileDescriptor(fd);
                    } catch (ErrnoException e) {
                        throw new RemoteException("Failed to open: " + e.getMessage());
                    }
                }
            };

            int ret = PackageManager.INSTALL_SUCCEEDED;
			// 真正的文件拷贝
            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Log.e(TAG, "Failed to copy package");
                return ret;
            }
			// 获取库的跟目录
            final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
            NativeLibraryHelper.Handle handle = null;
            try {
                handle = NativeLibraryHelper.Handle.create(codeFile);
				// 拷贝 Native代码 即so文件
                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                        abiOverride);
            } catch (IOException e) {
                Log.e(TAG, "Copying native libraries failed", e);
                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
            } finally {
                IoUtils.closeQuietly(handle);
            }

            return ret;
        }

 4. handleReturnCode分析
在HandlerParams的startCopy函数中,handleStartCopy执行完之后,将调用handleReturnCode开展后续工作,代码如下:
PackageManagerService.java::InstallParams.HandleParams

 void handleReturnCode() {
            // If mArgs is null, then MCS couldn't be reached. When it
            // reconnects, it will try again to install. At that point, this
            // will succeed.
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);
            }
        }
  private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        // Queue up an async operation since the package installation may take a little while.
       
         // 向mHandler中发送一个Runnable对象,这里是异步操作,因为安装一个程序包可能需要一些时间
         //一般currentStatus=1
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);// 清除任务
                 // Result object to be returned
                PackageInstalledInfo res = new PackageInstalledInfo(); // 创建一个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) {
                     // 安装阶段,调用installPackageLI进行安装
                        installPackageTracedLI(args, res);
                    }
                    args.doPostInstall(res.returnCode, res.uid); // 清除一些临时文件
                }

                // A restore should be performed at this point if (a) the install
                // succeeded, (b) the operation is not an update, and (c) the new
                // package has not opted out of backup participation.
                final boolean update = res.removedInfo != null
                        && res.removedInfo.removedPackage != null;
                final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
                boolean doRestore = !update
                        && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);

                // Set up the post-install work request bookkeeping.  This will be used
                // and cleaned up by the post-install event handling regardless of whether
                // there's a restore pass performed.  Token values are >= 1.
                int token;//计算一个ID号
                if (mNextInstallToken < 0) mNextInstallToken = 1;
                token = mNextInstallToken++;

                PostInstallData data = new PostInstallData(args, res);
                mRunningInstalls.put(token, data);//保存到mRunningInstalls结构中,以token为key
                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
                 // 安装成功,且需要备份的情况
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
                    // Pass responsibility to the Backup Manager.  It will perform a
                    // restore if appropriate, then pass responsibility back to the
                    // Package Manager to run the post-install observer callbacks
                    // and broadcasts.
                    IBackupManager bm = IBackupManager.Stub.asInterface(
                            ServiceManager.getService(Context.BACKUP_SERVICE));
                    if (bm != null) {
                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token
                                + " to BM for possible restore");
                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                        try {
                            // TODO: http://b/22388012
                            if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
                                bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
                            } else {
                                doRestore = false;
                            }
                        } catch (RemoteException e) {
                            // can't happen; the backup manager is local
                        } catch (Exception e) {
                            Log.e(TAG, "Exception trying to enqueue restore", e);
                            doRestore = false;
                        }
                    } else {
                        Log.e(TAG, "Backup Manager not found!");
                        doRestore = false;
                    }
                }

                if (!doRestore) {
                    // No restore possible, or the Backup Manager was mysteriously not
                    // available -- just fire the post-install work request directly.
                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);

                    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
				  //抛一个POST_INSTALL消息给mHandler进行处理 adb 等待安装结果
                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
                    mHandler.sendMessage(msg);
                }
            }
        });
    }

由上面代码可知,handleReturnCode主要做了4件事情:

  • 调用InstallArgs的doPreInstall函数,在本例中是FileInstallArgs的doPreInstall函数。
  • 调用PKMS的installPackageLI函数进行APK安装,该函数内部将调用InstallArgs的doRename对临时文件进行改名。另外,还需要扫描此APK文件。此过程和之前介绍的“扫描系统Package”一节的内容类似。至此,该APK中的私有财产就全部被登记到PKMS内部进行保存了。
  • 调用InstallArgs的doPostInstall函数,在本例中是FileInstallArgs的doPostInstall函数。
  • 此时,该APK已经安装完成(不论失败还是成功),继续向mHandler抛送一个POST_INSTALL消息,该消息携带一个token,通过它可从mRunningInstalls数组中取得一个PostInstallData对象

 

 private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
            installPackageLI(args, res);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
 private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
    Log.i(" PackageManagerService-xiao", "PackageManagerService installPackageLI");
	//获取 installFlags属性,这个属性表明APP安装到哪里
        final int installFlags = args.installFlags;
	    // 安装包应用程序的 包名
        final String installerPackageName = args.installerPackageName;
		 // volume的Uuid
        final String volumeUuid = args.volumeUuid;
		  //根据安装包代码的路径生成一个临时文件
        final File tmpPackageFile = new File(args.getCodePath());
        final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
		// 是否安装到外部存储
        final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
                || (args.volumeUuid != null));
		 // 新安装还是更新安装的标志位
        final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
        final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
        final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
        final boolean virtualPreload =
                ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
        boolean replace = false;
        int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
        if (args.move != null) {
            // moving a complete application; perform an initial scan on the new install location
            scanFlags |= SCAN_INITIAL;
        }
        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
            scanFlags |= SCAN_DONT_KILL_APP;
        }
        if (instantApp) {
            scanFlags |= SCAN_AS_INSTANT_APP;
        }
        if (fullApp) {
            scanFlags |= SCAN_AS_FULL_APP;
        }
        if (virtualPreload) {
            scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
        }

        // Result object to be returned
        res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
        res.installerPackageName = installerPackageName;

        if (DEBUG_INSTALL) Log.d(TAG, "installPackageLI: path=" + tmpPackageFile);

        // Sanity check
        if (instantApp && (forwardLocked || onExternal)) {
            Log.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
                    + " external=" + onExternal);
            res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
            return;
        }

        // Retrieve PackageSettings and parse package
        // 获取解析包配置的标志位
        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 {
			// 解析APK,主要是解析AndroidManifest.xml文件,将结果记录在PackageParser.Package中
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        } catch (PackageParserException e) {
            res.setError("Failed parse during installPackageLI", e);
            return;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        // Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
        //sdk版本检查
        if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
            Log.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) {
            Log.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 names
            renameStaticSharedLibraryPackage(pkg);

            // No static shared libs on external storage
            if (onExternal) {
                Log.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;
            }
        }

        // If we are installing a clustered package add results for the children
        Log.i(" PackageManagerService-xiao", "PackageManagerService installPackageLI pkg.childPackages:"+pkg.childPackages);
		//一个APK拆分成几个apk的情况
        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);
                }
            }
        }

        // If package doesn't declare API override, mark that we have an install
        // time CPU ABI override.
        if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
            pkg.cpuAbiOverride = args.abiOverride;
        }

        String pkgName = res.name = pkg.packageName;
		// 如果这个待安装的APP不是测试包,但是如果环境为仅允许测试包则返回
        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
            if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
                res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
                return;
            }
        }

        try {
            // either use what we've been given or parse directly from the APK
            if (args.certificates != null) {
                try {
                    PackageParser.populateCertificates(pkg, args.certificates);
                } catch (PackageParserException e) {
                    // there was something wrong with the certificates we were given;
                    // try to pull them from the APK
                    PackageParser.collectCertificates(pkg, parseFlags);
                }
            } else {
                PackageParser.collectCertificates(pkg, parseFlags);
            }
        } catch (PackageParserException e) {
            res.setError("Failed collect during installPackageLI", e);
            return;
        }

        // Get rid of all references to package scan path via parser.
        pp = null;
        String oldCodePath = null;
        boolean systemApp = false;
        synchronized (mPackages) {
            // Check if installing already existing package

			// 如果安装的升级应用,继续使用以前的老包名
            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
Log.i(" PackageManagerService-xiao", "PackageManagerService installPackageLI PackageManager.INSTALL_REPLACE_EXISTING");
                String oldName = mSettings.getRenamedPackageLPr(pkgName);
                if (pkg.mOriginalPackages != null
                        && pkg.mOriginalPackages.contains(oldName)
                        && mPackages.containsKey(oldName)) {
                    // This package is derived from an original package,
                    // and this device has been updating from that original
                    // name.  We must continue using the original name, so
                    // rename the new package here.
                     // 如果要进行安装的应用,已经存在,将是替换安装,则设置replace=true
                    pkg.setPackageName(oldName);
                    pkgName = pkg.packageName;
                    replace = true;
                    if (DEBUG_INSTALL) Log.d(TAG, "Replacing existing renamed package: oldName="
                            + oldName + " pkgName=" + pkgName);
                } else if (mPackages.containsKey(pkgName)) {
                    // This package, under its official name, already exists
                    // on the device; we should replace it.
                    replace = true;
                    if (DEBUG_INSTALL) Log.d(TAG, "Replace existing pacakge: " + pkgName);
                }

                // Child packages are installed through the parent package
                if (pkg.parentPackage != null) {
                    res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                            "Package " + pkg.packageName + " is child of package "
                                    + pkg.parentPackage.parentPackage + ". Child packages "
                                    + "can be updated only through the parent package.");
                    return;
                }

                if (replace) {
                    // Prevent apps opting out from runtime permissions
                    // 如果是替换,即升级安装
                    PackageParser.Package oldPackage = mPackages.get(pkgName);
                    final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
                    final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
					 // 如果老的TargetSdk 大于android 5.1 而新的TargetSdk 小于5.1,
                    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                            && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                        res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
                                "Package " + pkg.packageName + " new target SDK " + newTargetSdk
                                        + " doesn't support runtime permissions but the old"
                                        + " target SDK " + oldTargetSdk + " does.");
                        return;
                    }
                    // Prevent apps from downgrading their targetSandbox.
                    final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
                    final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
                    if (oldTargetSandbox == 2 && newTargetSandbox != 2) {
                        res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
                                "Package " + pkg.packageName + " new target sandbox "
                                + newTargetSandbox + " is incompatible with the previous value of"
                                + oldTargetSandbox + ".");
                        return;
                    }

                    // Prevent installing of child packages
                    if (oldPackage.parentPackage != null) {
                        res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                                "Package " + pkg.packageName + " is child of package "
                                        + oldPackage.parentPackage + ". Child packages "
                                        + "can be updated only through the parent package.");
                        return;
                    }
                }
            }

            PackageSetting ps = mSettings.mPackages.get(pkgName);
	 // 如果 ps 不为null,同样说明,已经存在一个具有相同安装包包名的程序,被安装,所以还是处理覆盖安装的问题。
    // 这里主要验证包名的签名,不一致的话,是不能覆盖安装的,另外版本号也不能比安装的地,否则不能替换安装
            if (ps != null) {
                if (DEBUG_INSTALL) Log.d(TAG, "Existing package: " + ps);

                // Static shared libs have same package with different versions where
                // we internally use a synthetic package name to allow multiple versions
                // of the same package, therefore we need to compare signatures against
                // the package setting for the latest library version.
                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;
                    }
                }
				// 判断安装的应用是否存在同名的应用,如果存在,判断应用是否带有系统应用的标志
                oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                    systemApp = (ps.pkg.applicationInfo.flags &
                            ApplicationInfo.FLAG_SYSTEM) != 0;
                }
                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            }
// 检查APK中定义的所有的权限是否已经被其他应用定义了,如果重定义的是系统应用定义的权限,
//那么忽略本app定义的这个权限。如果重定义的是非系统引用的权限,那么本次安装就以失败返回。

            int N = pkg.permissions.size();
            for (int i = N-1; i >= 0; i--) {
                PackageParser.Permission perm = pkg.permissions.get(i);
                BasePermission bp = mSettings.mPermissions.get(perm.info.name);

                // Don't allow anyone but the system to define ephemeral permissions.
                if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                        && !systemApp) {
                    Log.w(TAG, "Non-System package " + pkg.packageName
                            + " attempting to delcare ephemeral permission "
                            + perm.info.name + "; Removing ephemeral.");
                    perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
                }
                // Check whether the newly-scanned package wants to define an already-defined perm
                if (bp != null) {
                    // If the defining package is signed with our cert, it's okay.  This
                    // also includes the "updating the same package" case, of course.
                    // "updating same package" could also involve key-rotation.
                    final boolean sigsOk;
                    if (bp.sourcePackage.equals(pkg.packageName)
                            && (bp.packageSetting instanceof PackageSetting)
                            && (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,
                                    scanFlags))) {
                        sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
                    } else {
                        sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
                                pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
                    }
                    if (!sigsOk) {
                        // If the owning package is the system itself, we log but allow
                        // install to proceed; we fail the install on all other permission
                        // redefinitions.
                        if (!bp.sourcePackage.equals("android")) {
                            res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
                                    + pkg.packageName + " attempting to redeclare permission "
                                    + perm.info.name + " already owned by " + bp.sourcePackage);
                            res.origPermission = perm.info.name;
                            res.origPackage = bp.sourcePackage;
                            return;
                        } else {
                            Log.w(TAG, "Package " + pkg.packageName
                                    + " attempting to redeclare system permission "
                                    + perm.info.name + "; ignoring new declaration");
                            pkg.permissions.remove(i);
                        }
                    } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
                        // Prevent apps to change protection level to dangerous from any other
                        // type as this would allow a privilege escalation where an app adds a
                        // normal/signature permission in other app's group and later redefines
                        // it as dangerous leading to the group auto-grant.
                        if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                                == PermissionInfo.PROTECTION_DANGEROUS) {
                            if (bp != null && !bp.isRuntime()) {
                                Log.w(TAG, "Package " + pkg.packageName + " trying to change a "
                                        + "non-runtime permission " + perm.info.name
                                        + " to runtime; keeping old protection level");
                                perm.info.protectionLevel = bp.protectionLevel;
                            }
                        }
                    }
                }
            }
        }

        /// M: Operator APP support
         // 如果是带带有系统应用标志的应用,却要安装在SD卡上,则报错返回,安装失败原因错误的安装路径
        if (systemApp || sPmsExt.isOperatorApp(mPackages, mSettings.mPackages, pkgName)) {
            if (onExternal) {
                // Abort update; system app can't be replaced with app on sdcard
                res.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 app
                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                        "Cannot update a system app with an instant app");
                return;
            }
        }
   // 如果是移动APP
	Log.i(" PackageManagerService-xiao", "installPackageLI	args.move"+args.move);
        if (args.move != null) {
            // We did an in-place move, so dex is ready to roll
            scanFlags |= SCAN_NO_DEX;
            scanFlags |= SCAN_MOVE;

            synchronized (mPackages) {
                final PackageSetting ps = mSettings.mPackages.get(pkgName);
                if (ps == null) {
                    res.setError(INSTALL_FAILED_INTERNAL_ERROR,
                            "Missing settings for moved package " + pkgName);
                }

                // We moved the entire application as-is, so bring over the
                // previously derived ABI information.
                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
            }

        } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {//安装apk的情况
            // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
            scanFlags |= SCAN_NO_DEX;

            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) {
                Log.e(TAG, "Error deriving application ABI", pme);
                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
                return;
            }

            // Shared libraries for the package need to be updated.
            synchronized (mPackages) {
                try {
                    updateSharedLibrariesLPr(pkg, null);//更新sharedlib库
                } catch (PackageManagerException e) {
                    Log.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
                }
            }
        }
		// 重命名,将/data/app/vmdl{安装会话}.tmp重命名为data/app/包名-suffix
		// /data/app/vmdl636355084.tmp to /data/app/kr.hwangti.batterylog-D9rVNrKDGBnxt7CIXwcJyg==

        if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
            res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
            return;
        }

		Log.d(TAG, " installPackageLI instantApp: " + instantApp);

        if (!instantApp) {
            startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
        } else {
            if (DEBUG_DOMAIN_VERIFICATION) {
                Log.d(TAG, "Not verifying instant app install for app links: " + pkgName);
            }
        }

        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);
            }
        }

        // Check whether we need to dexopt the app.
        //
        // NOTE: it is IMPORTANT to call dexopt:
        //   - after doRename which will sync the package data from PackageParser.Package and its
        //     corresponding ApplicationInfo.
        //   - after installNewPackageLIF or replacePackageLIF which will update result with the
        //     uid of the application (pkg.applicationInfo.uid).
        //     This update happens in place!
        //
        // We only need to dexopt if the package meets ALL of the following conditions:
        //   1) it is not forward locked.
        //   2) it is not on on an external ASEC container.
        //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
        //
        // Note that we do not dexopt instant apps by default. dexopt can take some time to
        // complete, so we skip this step during installation. Instead, we'll take extra time
        // the first time the instant app starts. It's preferred to do it this way to provide
        // continuous progress to the useur instead of mysteriously blocking somewhere in the
        // middle of running an instant app. The default behaviour can be overridden
        // via gservices.
        final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
                && !forwardLocked
                && !pkg.applicationInfo.isExternalAsec()
                && (!instantApp || Global.getInt(mContext.getContentResolver(),
                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 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);
            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
                    null /* instructionSets */,
                    getOrCreateCompilerPackageStats(pkg),
                    mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
                    dexoptOptions);
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        // Notify BackgroundDexOptService that the package has been changed.
        // If this is an update of a package which used to fail to compile,
        // BackgroundDexOptService will remove it from its blacklist.
        // TODO: Layering violation
        BackgroundDexOptService.notifyPackageChanged(pkg.packageName);

        synchronized (mPackages) {
            final PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
                ps.setUpdateAvailable(false /*updateAvailable*/);
            }

            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
            for (int i = 0; i < childCount; i++) {
                PackageParser.Package childPkg = pkg.childPackages.get(i);
                PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                if (childPs != null) {
                    childRes.newUsers = childPs.queryInstalledUsers(
                            sUserManager.getUserIds(), true);
                }
            }

            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                updateSequenceNumberLP(ps, res.newUsers);
                updateInstantAppInstallerLocked(pkgName);
            }
        }
    }

POST_INSTALL处理

 case POST_INSTALL: {
                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
					// 我们知道msg的arg1是token,arg2是0

                    PostInstallData data = mRunningInstalls.get(msg.arg1);
                    final boolean didRestore = (msg.arg2 != 0);
					// 因为已经安装成功了,所以在 正在安装列表中删除了这个选项
                    mRunningInstalls.delete(msg.arg1);

                    if (data != null) {
                        InstallArgs args = data.args;
                        PackageInstalledInfo parentRes = data.res;
					// 如果已经成功的安装了应用,在发送广播之前先授予一些必要的权限
					// 这些权限在 installPackageAsUser 中创建 InstallParams 时传递的,为null。
                     //INSTALL_GRANT_RUNTIME_PERMISSIONS 这个属性在PackageManagerShellCommand.java 参数是-g给予的
                        final boolean grantPermissions = (args.installFlags
                                & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
                        final boolean killApp = (args.installFlags
                                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                        final boolean virtualPreload = ((args.installFlags
                                & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
                        final String[] grantedPermissions = args.installGrantPermissions;

                        // Handle the parent package
                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
                                virtualPreload, grantedPermissions, didRestore,
                                args.installerPackageName, args.observer);

                        // Handle the child packages
                        final int childCount = (parentRes.addedChildPackages != null)
                                ? parentRes.addedChildPackages.size() : 0;
                        for (int i = 0; i < childCount; i++) {
                            PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
                            handlePackagePostInstall(childRes, grantPermissions, killApp,
                                    virtualPreload, grantedPermissions, false /*didRestore*/,
                                    args.installerPackageName, args.observer);
                        }

                        // Log tracing if needed
                        if (args.traceMethod != null) {
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
                                    args.traceCookie);
                        }
                    } else {
                        Log.e(TAG, "Bogus post-install token " + msg.arg1);
                    }

                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
                } break;
 private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, boolean virtualPreload, String[] grantedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver) {
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
            // Send the removed broadcasts
            if (res.removedInfo != null) {
                res.removedInfo.sendPackageRemovedBroadcasts(killApp);
            }

            // Now that we successfully installed the package, grant runtime
            // permissions if requested before broadcasting the install. Also
            // for legacy apps in permission review mode we clear the permission
            // review flag which is used to emulate runtime permissions for
            // legacy apps.
            //动态权限的检查  
            if (grantPermissions) {
                grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
            }

            final boolean update = res.removedInfo != null
                    && res.removedInfo.removedPackage != null;
            final String installerPackageName =
                    res.installerPackageName != null
                            ? res.installerPackageName
                            : res.removedInfo != null
                                    ? res.removedInfo.installerPackageName
                                    : null;

            /// M: CTA requirement - permission control  @{
            grantCtaRuntimePerm(update, res);
            //@}

            // If this is the first time we have child packages for a disabled privileged
            // app that had no children, we grant requested runtime permissions to the new
            // children if the parent on the system image had them already granted.
            if (res.pkg.parentPackage != null) {
                synchronized (mPackages) {
                    grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
                }
            }

            synchronized (mPackages) {
                mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
            }

            final String packageName = res.pkg.applicationInfo.packageName;

            // Determine the set of users who are adding this package for
            // the first time vs. those who are seeing an update.
            int[] firstUsers = EMPTY_INT_ARRAY;
            int[] updateUsers = EMPTY_INT_ARRAY;
            final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
            final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
            for (int newUser : res.newUsers) {
                if (ps.getInstantApp(newUser)) {
                    continue;
                }
                if (allNewUsers) {
                    firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
                    continue;
                }
                boolean isNew = true;
                for (int origUser : res.origUsers) {
                    if (origUser == newUser) {
                        isNew = false;
                        break;
                    }
                }
                if (isNew) {
                    firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
                } else {
                    updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
                }
            }

            // Send installed broadcasts if the package is not a static shared lib.
            if (res.pkg.staticSharedLibName == null) {
                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);

                // Send added for users that see the package for the first time
                // sendPackageAddedForNewUsers also deals with system apps
                int appId = UserHandle.getAppId(res.uid);
                boolean isSystem = res.pkg.applicationInfo.isSystemApp();
                sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
                        virtualPreload /*startReceiver*/, appId, firstUsers);

                // Send added for users that don't see the package for the first time
                Bundle extras = new Bundle(1);
                extras.putInt(Intent.EXTRA_UID, res.uid);
                if (update) {
                    extras.putBoolean(Intent.EXTRA_REPLACING, true);
                }
				//发送一个广播,apk安装完成
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/,
                        null /*targetPackage*/, null /*finishedReceiver*/, updateUsers);

                ///M: MTK Power: Disable installation boost
                if (mPowerHalManager != null) {
                    mPowerHalManager.setInstallationBoost(false);
                }

                if (installerPackageName != null) {
					//发送一个更新的广播
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                            extras, 0 /*flags*/,
                            installerPackageName, null /*finishedReceiver*/, updateUsers);
                }

                // Send replaced for users that don't see the package for the first time
                if (update) {
					//apk升级
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                            packageName, extras, 0 /*flags*/,
                            null /*targetPackage*/, null /*finishedReceiver*/,
                            updateUsers);
                    if (installerPackageName != null) {
                        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                                extras, 0 /*flags*/,
                                installerPackageName, null /*finishedReceiver*/, updateUsers);
                    }
                    sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                            null /*package*/, null /*extras*/, 0 /*flags*/,
                            packageName /*targetPackage*/,
                            null /*finishedReceiver*/, updateUsers);
                } else if (launchedForRestore && !isSystemApp(res.pkg)) {
                    // First-install and we did a restore, so we're responsible for the
                    // first-launch broadcast.
                    if (DEBUG_BACKUP) {
                        Log.i(TAG, "Post-restore of " + packageName
                                + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
                    }
					//启动广播
                    sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
                }

                // Send broadcast package appeared if forward locked/external for all users
                // treat asec-hosted packages like removable media on upgrade
                if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
                    if (DEBUG_INSTALL) {
                        Log.i(TAG, "upgrading pkg " + res.pkg
                                + " is ASEC-hosted -> AVAILABLE");
                    }
                    final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
                    ArrayList<String> pkgList = new ArrayList<>(1);
                    pkgList.add(packageName);
                    sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
                }
            }

            // Work that needs to happen on first install within each user
            if (firstUsers != null && firstUsers.length > 0) {
                synchronized (mPackages) {
                    for (int userId : firstUsers) {
                        // If this app is a browser and it's newly-installed for some
                        // users, clear any default-browser state in those users. The
                        // app's nature doesn't depend on the user, so we can just check
                        // its browser nature in any user and generalize.
                        if (packageIsBrowser(packageName, userId)) {
                            mSettings.setDefaultBrowserPackageNameLPw(null, userId);
                        }

                        // We may also need to apply pending (restored) runtime
                        // permission grants within these users.
                        mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
                    }
                }
            }

            // Log current value of "unknown sources" setting
            EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                    getUnknownSourcesSettings());

            // Remove the replaced package's older resources safely now
            // We delete after a gc for applications  on sdcard.
            if (res.removedInfo != null && res.removedInfo.args != null) {
                Runtime.getRuntime().gc();
                synchronized (mInstallLock) {
                    res.removedInfo.args.doPostDeleteLI(true);
                }
            } else {
                // Force a gc to clear up things. Ask for a background one, it's fine to go on
                // and not block here.
                VMRuntime.getRuntime().requestConcurrentGC();
            }

            // Notify DexManager that the package was installed for new users.
            // The updated users should already be indexed and the package code paths
            // should not change.
            // Don't notify the manager for ephemeral apps as they are not expected to
            // survive long enough to benefit of background optimizations.
            for (int userId : firstUsers) {
                PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
                // There's a race currently where some install events may interleave with an uninstall.
                // This can lead to package info being null (b/36642664).
                if (info != null) {
                    mDexManager.notifyPackageInstalled(info, userId);
                    /// M: Removable system app support
                    sPmsExt.onPackageAdded(packageName, userId);
                }
            }
        }

        // If someone is watching installs - notify them
        if (installObserver != null) {
            try {
                Bundle extras = extrasForInstallResult(res);
                installObserver.onPackageInstalled(res.name, res.returnCode,
                        res.returnMsg, extras);
            } catch (RemoteException e) {
                Log.i(TAG, "Observer no longer exists.");
            }
        }
    }

运行到这里整个apk的安装就完成了,如果需要增加app的动态权限可以在handlePackagePostInstall里面实现。

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
android adb shell 命令大全 1. 显示系统中全部Android平台: android list targets 2. 显示系统中全部AVD(模拟器): android list avd 3. 创建AVD(模拟器): android create avd --name 名称 --target 平台编号 4. 启动模拟器: emulator -avd 名称 -sdcard ~/名称.img (-skin 1280x800) 5. 删除AVD(模拟器): android delete avd --name 名称 6. 创建SDCard: mksdcard 1024M ~/名称.img 7. AVD(模拟器)所在位置: Linux(~/.android/avd) Windows(C:\Documents and Settings\Administrator\.android\avd) 8. 启动DDMS: ddms 9. 显示当前运行的全部模拟器: adb devices 10. 对某一模拟器执行命令: abd -s 模拟器编号 命令 11. 安装应用程序: adb install -r 应用程序.apk 12. 获取模拟器中的文件: adb pull 13. 向模拟器中写文件: adb push 14. 进入模拟器的shell模式: adb shell 15. 启动SDK,文档,实例下载管理器: android 16. 缷载apk包: adb shell cd data/app rm apk包 exit adb uninstall apk包的主包名 adb install -r apk包 17. 查看adb命令帮助信息: adb help 18. 在命令行中查看LOG信息: adb logcat -s 标签名 19. adb shell后面跟的命令主要来自: 源码\system\core\toolbox目录和源码\frameworks\base\cmds目录。 20. 删除系统应用: adb remount (重新挂载系统分区,使系统分区重新可写)。 adb shell cd system/app rm *.apk 21. 获取管理员权限: adb root 22. 启动Activity: adb shell am start -n 包名/包名+类名(-n 类名,-a action,-d date,-m MIME-TYPE,-c category,-e 扩展数据,等)。 23、发布端口: 你可以设置任意的端口号,做为主机向模拟器或设备的请求端口。如: adb forward tcp:5555 tcp:8000 24、复制文件: 你可向一个设备或从一个设备中复制文件, 复制一个文件或目录到设备或模拟器上: adb push 如:adb push test.txt /tmp/test.txt 从设备或模拟器上复制一个文件或目录: adb pull 如:adb pull /addroid/lib/libwebcore.so . 25、搜索模拟器/设备的实例: 取得当前运行的模拟器/设备的实例的列表及每个实例的状态: adb devices 26、查看bug报告: adb bugreport 27、记录无线通讯日志: 一般来说,无线通讯的日志非常多,在运行时没必要去记录,但我们还是可以通过命令,设置记录: adb shell logcat -b radio 28、获取设备的ID和序列号: adb get-product adb get-serialno 29、访问数据库SQLite3 adb shell sqlite3 #cd system/sd/data //进入系统内指定文件夹 #ls //列表显示当前文件夹内容 #rm -r xxx //删除名字为xxx的文件夹及其里面的所有文件 #rm xxx //删除文件xxx #rmdir xxx //删除xxx的文件夹
class Session { //mysql的主机地址 const db_host = "localhost"; //需要第三方指定ip地址 //数据库用户名 const db_user = "root"; //需要第三方指定自己的用户名 //数据库密码 const db_pwd = ""; //需要第三方指定自己的库据库密码 //数据库 const db_name = "thinkphp"; //需要第三方指定数据库 //数据库表 const db_table = "tbl_session"; //需要第三方指定数据表 //mysql-handle private $db_handle; //session-lifetime private $lifeTime; function open($savePath, $sessName) { // get session-lifetime $this--->lifeTime = get_cfg_var("session.gc_maxlifetime"); // open database-connection $db_handle = @mysql_connect(self::db_host, self::db_user, self::db_pwd); $dbSel = @mysql_select_db(self::db_name, $db_handle); // return success if(!$db_handle || !$dbSel) return false; $this->db_handle = $db_handle; return true; } function close() { $this->gc(ini_get('session.gc_maxlifetime')); // close database-connection return @mysql_close($this->db_handle); } function read($sessID) { // fetch session-data $res = @mysql_query("SELECT session_data AS d FROM ".self::db_table." WHERE session_id = '$sessID' AND session_expires > ".time(), $this->db_handle); // return data or an empty string at failure if($row = @mysql_fetch_assoc($res)) return $row['d']; return ""; } function write($sessID, $sessData) { // new session-expire-time $newExp = time() + $this->lifeTime; // is a session with this id in the database? $res = @mysql_query("SELECT * FROM ".self::db_table." WHERE session_id = '$sessID'", $this->db_handle); // if yes, if(@mysql_num_rows($res)) { // ...update session-data @mysql_query("UPDATE ".self::db_table." SET session_expires = '$newExp', session_data = '$sessData' WHERE session_id = '$sessID'", $this->db_handle); // if something happened, return true if(@mysql_affected_rows($this->db_handle)) return true; } else // if no session-data was found, { // create a new row @mysql_query("INSERT INTO ".self::db_table." ( session_id, session_expires, session_data) VALUES( '$sessID', '$newExp', '$sessData')", $this->db_handle); // if row was created, return true if(@mysql_affected_rows($this->db_handle)) return true; } // an unknown error occured return false; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值