Android-0.PMS简介及VirtualApp中安装App全流程

7 篇文章 6 订阅

1.Package Manager简介

包指的是Apk、jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一个机制来进行包的加载、解析、管理等操作,这就是包管理机制。包管理机制由许多类一起组成,其中核心为PackageManagerServicePMS),它负责对包进行管理。

PackageManager是一个抽象类,具体实现类为ApplicationPackageManagerApplicationPackageManager中的方法会通过IPackageManagerPMS进行进程间通信,因此PackageManager所提供的功能最终是由PMS来实现的。

Package Manager的功能主要包含以下部分:

  1. 获取一个应用程序的所有信息(ApplicationInfo
  2. 获取ActivityProviderReceiverService四大组件的信息
  3. 权限处理,包括对系统和应用定义的PermissionPermission Group信息的增加、删除、查询和检查
  4. 获取包的信息,查询包的UIDGID、包名、系统默认程序等信息
  5. 安装、卸载APK

APK的安装场景主要有以下几种:

  1. 通过adb命令安装:adb 命令包括adb push/install
  2. 用户下载的Apk,通过系统安装器packageinstaller安装该Apk。

最终都交由PMS来进行处理。

2.PackageInstaller简介

2.1 PackageInstaller初始化

代码参考AOSP 中 API 23 (android 6.0.1)

packageinstaller: http://androidxref.com/6.0.1_r10/xref/packages/apps/PackageInstaller/
它的AndroidManifest.xml显示入口为PackageInstallerActivity

        <activity android:name=".PackageInstallerActivity"
               android:configChanges="orientation|keyboardHidden|screenSize"
               android:excludeFromRecents="true">

当我们调用PackageInstaller来安装应用时会跳转到PackageInstallerActivity,并调用PackageInstallerActivityonCreate方法, 这个方法部分功能为:

  1. Intent获取相关数据
  2. 分别对package协议file协议的Uri进行处理,得到包信息PackageInfo
  3. 对不同来源Apk进行处理(已知来源直接调用initiateInstall安装,未知来源弹框提示)
    代码如下:
protected void onCreate(Bundle icicle) {
		...		
		// 1.从Intent获取相关数据
		 final Intent intent = getIntent();
        if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
            final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
            final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
         	....
            mSessionId = sessionId;
            mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath));
            mOriginatingURI = null;
            mReferrerURI = null;
        } else {
            mSessionId = -1;
            mPackageURI = intent.getData();
            mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
            mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
        }
        ...
     
 		final boolean unknownSourcesAllowedByAdmin = isUnknownSourcesAllowedByAdmin();
        final boolean unknownSourcesAllowedByUser = isUnknownSourcesEnabled();
		// 是否为未知来源的APK
        boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
 		...
 		// 2.分别对package协议和file协议的Uri进行处理,得到包信息PackageInfo
 		 final PackageUtil.AppSnippet as;
        if ("package".equals(mPackageURI.getScheme())) { // package协议
            mInstallFlowAnalytics.setFileUri(false);
        	
            mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
                        PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);
            ....
        } else { // file协议
            mInstallFlowAnalytics.setFileUri(true);
            final File sourceFile = new File(mPackageURI.getPath());
            PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);

           	....
            mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
                    PackageManager.GET_PERMISSIONS, 0, 0, null,
                    new PackageUserState());
           ...
        }
        mInstallFlowAnalytics.setPackageInfoObtained();
        ...
	    // 3.对不同来源Apk进行处理
	      if (!requestFromUnknownSource) { // 已知来源的Apk直接安装
            initiateInstall();
            return;
        }
        ....
        final boolean isManagedProfile = mUserManager.isManagedProfile();
        if (!unknownSourcesAllowedByAdmin
                || (!unknownSourcesAllowedByUser && isManagedProfile)) { // 禁止安装,就弹出提示Dialog
            showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
            mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
        } else if (!unknownSourcesAllowedByUser) { // 弹出询问框
            // Ask user to enable setting first
            showDialogInner(DLG_UNKNOWN_SOURCES);
            mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
        } else { // 允许安装未知来源的APK
            initiateInstall();
        }   

===>可以看到接着是调用了initiateInstall方法, 这个方法部分功能为:

  1. 得到包名
  2. 根据包名获取应用程序信息
  3. 调用startInstallConfirm初始化安装确认界面

代码如下:

  private void initiateInstall() {
        String pkgName = mPkgInfo.packageName; //1.得到包名
      	// 检查设备上是否已有包含此名称的包,但它已被重命名为其他内容
        String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
        if (oldName != null && oldName.length > 0 && oldName[0] != null) {
            pkgName = oldName[0];
            mPkgInfo.packageName = pkgName;
            mPkgInfo.applicationInfo.packageName = pkgName;
        }
        // Check if package is already installed. display confirmation dialog if replacing pkg
        try {
            // 2.根据包名获取应用程序信息
            mAppInfo = mPm.getApplicationInfo(pkgName,
                    PackageManager.GET_UNINSTALLED_PACKAGES);
            if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
                mAppInfo = null;
            }
        } catch (NameNotFoundException e) {
            mAppInfo = null;
        }

        mInstallFlowAnalytics.setReplace(mAppInfo != null);
        mInstallFlowAnalytics.setSystemApp(
                (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));
		// 3. 初始化安装确认界面
        startInstallConfirm();
    }

===>startInstallConfirm初始化并显示安装确认界面,就是我们平常安装APK时出现的界面,界面上有确认和取消按钮,并列出了安装该APK需要访问的系统权限,这个方法部分功能为:

  1. 初始化界面相关代码
  2. 界面列出安装该APK需要访问的系统权限
  3. 绑定监听安装按钮的事件

代码如下:

 private void startInstallConfirm() {
        // 1.初始化界面相关代码
		...
		// 2.列出安装该APK需要访问的系统权限,并显示
        AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
        final int N = perms.getPermissionCount(AppSecurityPermissions.WHICH_ALL);
        if (mAppInfo != null) {
            msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
                    ? R.string.install_confirm_question_update_system
                    : R.string.install_confirm_question_update;
            mScrollView = new CaffeinatedScrollView(this);
            mScrollView.setFillViewport(true);
            boolean newPermissionsFound = false;
            if (!supportsRuntimePermissions) {
                newPermissionsFound =
                        (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
                mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound);
                if (newPermissionsFound) {
                    permVisible = true;
                    mScrollView.addView(perms.getPermissionsView(
                            AppSecurityPermissions.WHICH_NEW));
                }
            }
            ....
        } else  {
            findViewById(R.id.tabscontainer).setVisibility(View.GONE);
            findViewById(R.id.divider).setVisibility(View.VISIBLE);
        }
        ....
        mInstallFlowAnalytics.setPermissionsDisplayed(permVisible);
       ....
        mInstallConfirm.setVisibility(View.VISIBLE);
        mOk = (Button)findViewById(R.id.ok_button); 
        mCancel = (Button)findViewById(R.id.cancel_button);
        mOk.setOnClickListener(this); // 3.绑定安装按钮事件
        mCancel.setOnClickListener(this);
        if (mScrollView == null) {
            // There is nothing to scroll view, so the ok button is immediately
            // set to install.
            mOk.setText(R.string.install);
            mOkCanInstall = true;
        } else {
            mScrollView.setFullScrollAction(new Runnable() {
                @Override
                public void run() {
                    mOk.setText(R.string.install);  // 安装按钮
                    mOkCanInstall = true;
                }
            });
        }
    }

简单总结下PackageInstaller初始化:

  1. 分别对package协议file协议的Uri进行处理,得到mPkgInfo
  2. 对不同来源Apk进行处理(已知来源直接调用initiateInstall安装,未知来源弹框提示)
  3. 如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就会初始化安装确认界面

2.2 PackageInstaller安装APK

用户点击安装确认界面的mOk 按钮,就会触发PackageInstallerActivityonClick方法,内部调用了startInstall方法,如下所示:

  public void onClick(View v) {
        if (v == mOk) {
            if (mOkCanInstall || mScrollView == null) {
                mInstallFlowAnalytics.setInstallButtonClicked();
                if (mSessionId != -1) {
                    mInstaller.setPermissionsResult(mSessionId, true);
                    mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult(
                            PackageManager.INSTALL_SUCCEEDED);
                    finish();
                } else {
                    startInstall(); // 安装函数
                }
            } else {
                mScrollView.pageScroll(View.FOCUS_DOWN);
            }
        } else if(v == mCancel) {
           ...
        }
    }

===>startInstall 启动了一个新的InstallAppProgress activity, 并把一些参数传了过去,代码如下:

 private void startInstall() {
        // Start subactivity to actually install the application
        Intent newIntent = new Intent();
        newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                mPkgInfo.applicationInfo);
        newIntent.setData(mPackageURI);
        newIntent.setClass(this, InstallAppProgress.class);
        //  省略传入部分参数代码
        ....
        if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
        startActivity(newIntent);
        finish();
    }

===>InstallAppProgress 类的onCreate函数先取得传入参数,再调用initView方法,代码如下:

    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
       //  省略传入部分参数代码
		...
        initView();
    }

===>InstallAppProgress 类的initView方法,代码如下:


    public void initView() {

        PackageManager pm = getPackageManager();
        try {
            PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, 
                    PackageManager.GET_UNINSTALLED_PACKAGES);
            if(pi != null) {
                installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            }
        } catch (NameNotFoundException e) {
        }
        if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
            Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
        }
		....
        if ("package".equals(mPackageURI.getScheme())) { // package协议
            try {
                pm.installExistingPackage(mAppInfo.packageName);
                observer.packageInstalled(mAppInfo.packageName,
                        PackageManager.INSTALL_SUCCEEDED);
            } catch (PackageManager.NameNotFoundException e) {
                observer.packageInstalled(mAppInfo.packageName,
                        PackageManager.INSTALL_FAILED_INVALID_APK);
            }
        } else {
            pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
                    installerPackageName, verificationParams, null);
        }
    }

===>精简了一下,主要是这两个方法:

  1. pm.installExistingPackage,实际上调用的就是ApplicationPackageManagerinstallExistingPackage,它是为其他用户安装已安装过的apk
  2. pm.installPackageWithVerificationAndEncryption,实际上调用的就是ApplicationPackageManagerinstallPackageWithVerificationAndEncryption,它是安装一个apk

这里我们只跟踪ApplicationPackageManagerinstallPackageWithVerificationAndEncryption, 最终内部是调用了 mPM.installPackage, 代码如下:

    public void installPackageWithVerificationAndEncryption(Uri packageURI,
            IPackageInstallObserver observer, int flags, String installerPackageName,
            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                installerPackageName, verificationParams, encryptionParams);
    }
    --->installCommon方法的实现如下:
        private void installCommon(Uri packageURI,
            PackageInstallObserver observer, int flags, String installerPackageName,
            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
        ...
        final String originPath = packageURI.getPath();
        try {
            mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
                    verificationParams, null);
        } catch (RemoteException ignored) {
        }
    }

===> mPM的定义为IPackageManager ,也就是IPackageManager.aidl,很明显,它最终是调到了PMSinstallPackage方法。

 IPackageManager mPM

总结下PackageInstaller安装APK,其实就是调到了PMSinstallPackage方法进行安装。

3. PMS简介

3.1 交互简介

从源码来分析:
ApplicationPackageManagerPackageManager的实现体,内部有成员变量IPackageManager mPM, ApplicationPackageManager是由ContextImpl.java初始化的,同时初始化的还有mPM变量

    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }

        IPackageManager pm = ActivityThread.getPackageManager(); // ApplicationPackageManager中的mPM
        if (pm != null) {
            // ApplicationPackageManager初始化
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }
        return null;
    }
    --->ApplicationPackageManager构造函数如下:
   ApplicationPackageManager(ContextImpl context,
                              IPackageManager pm) {
        mContext = context;
        mPM = pm;
    }
    ---> ActivityThread.getPackageManager如下:
        public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }

可以看出 mPM变量就是IPackageManager.Stub转换的代理IPackageManagerProxy。参考 aidl自动生成类分析

public class PackageManagerService extends IPackageManager.Stub {
}

1.PackageManagerServiceIPackageManager在服务端的接口
2.ApplicationPackageManagermPM成员或者ActivityThread.getPackageManager,是IPackageManager在客户端的代理接口,

3.2 PMS拷贝APK流程

PMSinstallPackage方法继续查看源码, 内部调用了installPackageAsUser方法

    public void installPackage(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride) {
        installPackageAsUser(originPath, observer, installFlags, installerPackageName,
                verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
    }
    

===>installPackageAsUser方法,这个方法部分功能为:

  1. 检查调用者是否有安装apk的权限
  2. 由于安装程序是一个耗时的过程,所以使用了Handler消息传递机制,发送INIT_COPY消息

代码如下:

    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride, int userId) {
        // 1.检查调用者是否有安装apk的权限
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
        ...

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

        // Only system components can circumvent runtime permissions when installing.
        if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
                && mContext.checkCallingOrSelfPermission(Manifest.permission
                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
            throw new SecurityException("You need the "
                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
                    + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
        }

        verificationParams.setInstallerUid(callingUid);

        final File originFile = new File(originPath);
        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);

        final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
                null, verificationParams, user, packageAbiOverride, null);
        // 2.由于安装程序是一个耗时的过程,所以使用了Handler消息传递机制,发送INIT_COPY消息
        mHandler.sendMessage(msg);
    }
   ---->mHandler的定义:
   final PackageHandler mHandler;

处理INIT_COPY类型的消息,这个方法部分功能为:

  1. connectToService用于标识是否绑定了DefaultContainerServiceDefaultContainerService是用于检查和复制可移动文件的服务,这是一个比较耗时的操作,因此DefaultContainerService没有和PMS运行在同一进程中,它运行在com.android.defcontainer进程,通过IMediaContainerServicePMS进行IPC通信
  2. 发送MCS_BOUND类型的消息,触发处理第一个安装请求

代码如下所示:

        void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    int idx = mPendingInstalls.size();
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
                    // mBound用于标识是否绑定了服务,默认值为false
                    if (!mBound) {
                         //如果没有绑定服务,重新绑定,connectToService方法内部如果绑定成功会将mBound置为true
                        if (!connectToService()) {
                            Slog.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                             //绑定服务失败则return
                            return;
                        } else {
                            //绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                      	 //已经绑定服务
                        mPendingInstalls.add(idx, params); // 加入待安装List
                        if (idx == 0) {
                            mHandler.sendEmptyMessage(MCS_BOUND);// 发送MCS_BOUND
                        }
                    }
                    break;

处理MCS_BOUND类型的消息, 如果待安装mPendingInstalls不为空,这个方法部分功能为:

  1. startCopy开始复制APK
  2. 如果APK安装成功,删除本次安装请求, mPendingInstalls.remove(0);
  3. 如果没有安装请求了,发送MCS_UNBIND解绑服务的请求
  4. 如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求

代码如下所示:

   case MCS_BOUND: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;
                    }
                    if (mContainerService == null) {
                        if (!mBound) {
                        	...
                            //  绑定失败,清空安装请求队列
                            mPendingInstalls.clear();
                        } else {
                            Slog.w(TAG, "Waiting to connect to media container service");
                        }
                    } else if (mPendingInstalls.size() > 0) {// 待安装List不为空
                        HandlerParams params = mPendingInstalls.get(0);
                        if (params != null) {
                            if (params.startCopy()) { // 1.开始复制APK
                                // We are done...  look for more work or to
                                // Delete pending install
                                 //2.如果APK安装成功,删除本次安装请求
                                if (mPendingInstalls.size() > 0) {
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) {
                                    if (mBound) {
										// 3.如果没有安装请求了,发送MCS_UNBIND解绑服务的请求
                                        removeMessages(MCS_UNBIND);
                                        Message ubmsg = obtainMessage(MCS_UNBIND);
                                        // Unbind after a little delay, to avoid
                                        // continual thrashing.
                                        sendMessageDelayed(ubmsg, 10000);
                                    }
                                } else {
                                     // 4.如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求    
                                    mHandler.sendEmptyMessage(MCS_BOUND);
                                }
                            }
                        }
                    } else {
                        // Should never happen ideally.
                        Slog.w(TAG, "Empty queue");
                    }
                    break;
                }

INIT_COPY的发送消息,我们可以知道InstallParamsHandlerParams真正实现体,代码如下:

final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
                null, verificationParams, user, packageAbiOverride, null);
--->InstallParams

前面关键函数是HandlerParamsstartCopy,也就是InstallParamsstartCopy,调用startCopy方法时会先自动加1,如果次数大于4次就放弃这个安装请求,代码如下:

  final boolean startCopy() {
            boolean res;
            try {
				 // 1.startCopy方法尝试的次数,超过了4次,就放弃这个安装请求
                if (++mRetries > MAX_RETRIES) {
              		...
                    return false;
                } else {
                    handleStartCopy(); // 2.调用handleStartCopy
                    res = true;
                }
            } catch (RemoteException e) {
                ...
            }
            handleReturnCode();
            return res;
        }

===>handleStartCopy方法在InstallParams中实现,这个方法部分功能为:

  1. 确定APK的安装位置。onSd:安装到SD卡, onInt:内部存储即Data分区
  2. 判断安装的位置
  3. 根据InstallParams创建InstallArgs对象, InstallArgs 是一个抽象类,定义了APK的安装逻辑,比如复制和重命名APK等,它有3个子类,都被定义在PMS中,如下图所示。
    private InstallArgs createInstallArgs(InstallParams params) {
        if (params.move != null) {
            return new MoveInstallArgs(params);
        } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
            return new AsecInstallArgs(params);
        } else {
            return new FileInstallArgs(params);
        }
    }

在这里插入图片描述
FileInstallArgs用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(Data分区)
AsecInstallArgs用于处理安装到ASEC中(mnt/asec)即SD卡中的APK
MoveInstallArgs用于处理已安装APK的移动的逻辑。
对APK进行检查后就会调用InstallArgscopyApk方法进行安装。

代码如下:

        public void handleStartCopy() throws RemoteException {
			...
 			// 1.确定APK的安装位置。onSd:安装到SD卡, onInt:内部存储即Data分区  
            final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;

            PackageInfoLite pkgLite = null;

            if (onInt && onSd) {
                // APK不能同时安装在SD卡和Data分区
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else {
                // 获取APK的少量的信息
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                        packageAbiOverride);
              ...
            if (ret == PackageManager.INSTALL_SUCCEEDED) {
            	// 2.判断安装的位置
                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) {
                   ...
                } else {
                    // Override with defaults if needed.
                    loc = installLocationPolicy(pkgLite);
                    ...
                }
            }
			//3.根据InstallParams创建InstallArgs对象
            final InstallArgs args = createInstallArgs(this);
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                 /*
                 * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
                 * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
                 */
                int userIdentifier = getUser().getIdentifier();
                if (userIdentifier == UserHandle.USER_ALL
                        && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
                    userIdentifier = UserHandle.USER_OWNER;
                }

                /*
                 * 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, userIdentifier);
                if (!origin.existing && requiredUid != -1
                        && isVerificationEnabled(userIdentifier, installFlags)) {

                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
                            mRequiredVerifierPackage, receivers);
                    if (ret == PackageManager.INSTALL_SUCCEEDED
                            && mRequiredVerifierPackage != null) {
 						...
 						// 一堆检查...
                    }
                } else {
                    /*
                     * No package verification is enabled, so immediately start
                     * the remote call to initiate copy using temporary file.
                     */
                    ret = args.copyApk(mContainerService, true);
                }
            }
            mRet = ret;
        }

===>InstallArgscopyApk方法, 不同的InstallArgs子类会有着不同的处理,这里以FileInstallArgs为例,这个方法部分功能为:

  1. 创建临时文件存储目录,如/data/app/vmdl123456.tmp,其中123456是安装的sessionId
  2. 通过IMediaContainerService跨进程调用DefaultContainerServicecopyPackage方法,这个方法会在DefaultContainerService所在的进程中将APK复制到临时存储目录,比如/data/app/vmdl 123456.tmp/base.apk

代码如下:

 int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
            if (origin.staged) {
            // 已经安装过了
                if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
                codeFile = origin.file;
                resourceFile = origin.file;
                return PackageManager.INSTALL_SUCCEEDED;
            }

            try {
            // 1.创建临时文件存储目录
                final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid);
                codeFile = tempDir;
                resourceFile = tempDir;
            } catch (IOException e) {
                Slog.w(TAG, "Failed to create copy file: " + e);
                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }
			...
            int ret = PackageManager.INSTALL_SUCCEEDED;
            // 2.通过IMediaContainerService跨进程调用DefaultContainerService的copyPackage方法
            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Slog.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);
                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                        abiOverride);
            } catch (IOException e) {
                Slog.e(TAG, "Copying native libraries failed", e);
                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
            } finally {
                IoUtils.closeQuietly(handle);
            }
            return ret;
        }

===>DefaultContainerServicecopyPackage,最终调用FileInputStream写入,代码流程如下:

        public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
            ...
                final File packageFile = new File(packagePath);
                pkg = PackageParser.parsePackageLite(packageFile, 0);
                return copyPackageInner(pkg, target);
          ...
        }
        ---->
   private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
            throws IOException, RemoteException {
        copyFile(pkg.baseCodePath, target, "base.apk");
        if (!ArrayUtils.isEmpty(pkg.splitNames)) {
            for (int i = 0; i < pkg.splitNames.length; i++) {
                copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");
            }
        }

        return PackageManager.INSTALL_SUCCEEDED;
    }
  ---->
    private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)
            throws IOException, RemoteException {
        Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(sourcePath);
            out = new ParcelFileDescriptor.AutoCloseOutputStream(
                    target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
            Streams.copy(in, out);
        } finally {
            IoUtils.closeQuietly(out);
            IoUtils.closeQuietly(in);
        }
    }

3.3 PMS安装APK流程

我们回到APK的复制调用链的头部方法:HandlerParamsstartCopy方法,在最后会调用InstallParamshandleReturnCode,代码如下所示:

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

===>processPendingInstall,这个方法部分功能为:

  1. args.doPreInstall安装前处理,检查APK的状态,在安装前确保安装环境的可靠,如果不可靠会清除复制的APK文件
  2. installPackageLI安装流程
  3. args.doPostInstall处理安装后的收尾操作,如果安装不成功,删除掉安装相关的目录与文件

代码如下:

    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        // Queue up an async operation since the package installation may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
                 // Result object to be returned
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.returnCode = currentStatus;
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = new PackageRemovedInfo();
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                	//  安装前处理
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                        installPackageLI(args, res);// 安装
                    }
                    // 安装后收尾
                    args.doPostInstall(res.returnCode, res.uid);
                }

                ....
        });
    }

===>installPackageLI安装流程,这个方法部分功能为:

  1. 创建PackageParser解析APK
  2. 检查APK是否存在,标志位replace置为true表示是替换安装
  3. 如果Settings中保存有要安装的APK的信息,说明此前安装过该APK,则需要校验APK的签名信息,确保安全的进行替换
  4. 遍历每个权限,对权限进行处理
  5. 将临时文件重新命名,比如前面提到的/data/app/vmdl123456.tmp/base.apk,重命名为/data/app/包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加,参考FileInstallArgsgetNextCodePath
  6. 替换安装或安装新的APK
  7. 更新应用程序所属的用户

代码如下:

    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
         ...
        PackageParser pp = new PackageParser();//1
        final PackageParser.Package pkg;
        try {
            // 1.创建PackageParser解析APK
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        } catch (PackageParserException e) {
            res.setError("Failed parse 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) {
            // 2. 检查APK的package是已存在,替换已存在的,也就是更新模式
            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                String oldName = mSettings.mRenamedPackages.get(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.
                    pkg.setPackageName(oldName);
                    pkgName = pkg.packageName;
                    replace = true;//设置标志位表示是替换安装
               
                }  
                ...
            }

            PackageSetting ps = mSettings.mPackages.get(pkgName);
            //3.查看Settings中是否存有要安装的APK的信息,如果有就获取签名信息
            if (ps != null) {
                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

                //检查签名的正确性
                if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
                    if (!checkUpgradeKeySetLP(ps, pkg)) {
                        res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                                + pkg.packageName + " upgrade keys do not match the "
                                + "previously installed version");
                        return;
                    }
                }
                ...
            }

            // Check whether the newly-scanned package wants to define an already-defined perm
            // 4.遍历每个权限,对权限进行处理
            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);
				...
            }

        }

        if (systemApp && onExternal) {
           // 系统APP不能在SD卡上替换安装
            res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
            return;
        }
        ...
       // 5.重命名临时文件
        if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
            res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
            return;
        }

        startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);

        if (replace) {
        	 //6.1 替换安装   
            replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                    installerPackageName, volumeUuid, res);
        } else {
        	// 6.2 安装新的APK
            installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                    args.user, installerPackageName, volumeUuid, res);
        }
        synchronized (mPackages) {
            final PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
            	// 7.更新应用程序所属的用户
                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            }
        }
    }

===>这里我们以新安装APK为例,会调用PMSinstallNewPackageLIF方法,这个方法部分功能为:

  1. 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK
  2. 更新Settings信息,Settings用于保存所有包的动态设置。
  3. 安装失败则删除APK

代码如下:

 private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
            UserHandle user, String installerPackageName, String volumeUuid,
            PackageInstalledInfo res) {
		...
        try {
        //1. 扫描APK
            PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
                    System.currentTimeMillis(), user);
			 // 2.更新Settings信息
            updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
            // delete the partially installed application. the data directory will have to be
            // restored if it was already existing
            if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                //3.安装失败则删除APK
                deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
                        dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
                                res.removedInfo, true);
            }

        } catch (PackageManagerException e) {
            res.setError("Package couldn't be installed in " + pkg.codePath, e);
        }
    }

===>updateSettingsLI中设置APK安装成功,代码如下:

    private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
            String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
            UserHandle user) {
        String pkgName = newPackage.packageName;
        synchronized (mPackages) {
            
            mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
            mSettings.writeLPr();
        }

        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);

        synchronized (mPackages) {
            updatePermissionsLPw(newPackage.packageName, newPackage,
                    UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
                            ? UPDATE_PERMISSIONS_ALL : 0));
            // For system-bundled packages, we assume that installing an upgraded version
            // of the package implies that the user actually wants to run that new code,
            // so we enable the package.
            PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                if (isSystemApp(newPackage)) {
                    // NB: implicit assumption that system package upgrades apply to all users
                    if (DEBUG_INSTALL) {
                        Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
                    }
                    if (res.origUsers != null) {
                        for (int userHandle : res.origUsers) {
                            ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
                                    userHandle, installerPackageName);
                        }
                    }
                    // Also convey the prior install/uninstall state
                    if (allUsers != null && perUserInstalled != null) {
                        for (int i = 0; i < allUsers.length; i++) {
                            if (DEBUG_INSTALL) {
                                Slog.d(TAG, "    user " + allUsers[i]
                                        + " => " + perUserInstalled[i]);
                            }
                            ps.setInstalled(perUserInstalled[i], allUsers[i]);
                        }
                        // these install state changes will be persisted in the
                        // upcoming call to mSettings.writeLPr().
                    }
                }
                // It's implied that when a user requests installation, they want the app to be
                // installed and enabled.
                int userId = user.getIdentifier();
                if (userId != UserHandle.USER_ALL) {
                    ps.setInstalled(true, userId);
                    ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
                }
            }
            res.name = pkgName;
            res.uid = newPackage.applicationInfo.uid;
            res.pkg = newPackage;
            // 安装完成状态
            mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
            mSettings.setInstallerPackageName(pkgName, installerPackageName);
            res.returnCode = PackageManager.INSTALL_SUCCEEDED;
            //to update install status
            mSettings.writeLPr();
        }

3.4 PMS创建流程

它和 AMS的创建是类似的,启动代码位于frameworks/base/services/java/com/android/server/SystemServer.java中,代码如下:

//  zygote的main入口
 public static void main(String[] args) {
   new SystemServer().run();
 }

===> SystemServer().run的部分代码:

 private void run() {
 // Initialize the system context.
 	createSystemContext();
	// Create the system service manager.
	mSystemServiceManager = new SystemServiceManager(mSystemContext);
	LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

	// Start services.
	try {
 		 traceBeginAndSlog("StartServices");
        //启动引导服务
        startBootstrapServices();//3
        //启动核心服务
        startCoreServices();//4
        //启动其他服务
        startOtherServices();//5
	}
 }

SystemServiceManager启动了ActivityManagerServicePowerManagerServicePackageManagerService等服务。
startCoreServices方法中则启动了DropBoxManagerServiceBatteryServiceUsageStatsServiceWebViewUpdateServic等服务。
startOtherServices方法中启动了CameraServiceAlarmManagerServiceVrManagerService等服务。

这些服务的父类均为SystemService

可以看出,官方把系统服务分为了三种类型,分别是引导服务、核心服务和其他服务,PMS属于引导服务

===>创建PMS的过程位于startBootstrapServices中,使用了PackageManagerService.main方法,代码如下:

private void startBootstrapServices() {
		...
		// 创建PMS
        Slog.i(TAG, "Package Manager");
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();

===>PackageManagerService.main方法 ,这个方法部分功能为:

  1. 创建PMS对象
  2. 将PMS注册到ServiceManager中
    public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // 1.创建PMS对象
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        // 2.将PMS注册到ServiceManager中
        ServiceManager.addService("package", m);
        return m;
    }

==>接着看PMS的构造过程,PMS的构造方法大概有600多行,分为5个阶段,每个阶段会打印出相应的EventLog,EventLog用于打印Android系统的事件日志。

  1. BOOT_PROGRESS_PMS_START(开始阶段)
  2. BOOT_PROGRESS_PMS_SYSTEM_SCAN_START(扫描系统阶段)
  3. BOOT_PROGRESS_PMS_DATA_SCAN_START(扫描Data分区阶段)
  4. BOOT_PROGRESS_PMS_SCAN_END(扫描结束阶段)
  5. BOOT_PROGRESS_PMS_READY(准备阶段)

代码如下:

3.4.1 开始阶段
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // 打印开始阶段日志
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());

        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }

        mContext = context;
        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
        // 用于存储屏幕的相关信息
        mMetrics = new DisplayMetrics();
        // Settings用于保存所有包的动态设置
        mSettings = new Settings(mPackages);
        // 在Settings中添加多个默认的sharedUserId//1
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

		...

        mInstaller = installer;
        // 创建Dex优化工具类
        mPackageDexOptimizer = new PackageDexOptimizer(this);
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
                FgThread.get().getLooper());

        getDefaultDisplayMetrics(context, mMetrics);
		// 得到全局系统配置信息
        SystemConfig systemConfig = SystemConfig.getInstance();
        // 获取全局的groupId 
        mGlobalGids = systemConfig.getGlobalGids();
        // 获取系统权限
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();

        synchronized (mInstallLock) {
         // 安装APK时需要的锁,保护所有对installd的访问。
        synchronized (mPackages) {//2
            // 创建后台线程ServiceThread
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
             // 创建PackageHandler绑定到ServiceThread的消息队列
            mHandler = new PackageHandler(mHandlerThread.getLooper());//3
             // 将PackageHandler添加到Watchdog的检测集中
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);//4
			// 在Data分区创建一些目录
            File dataDir = Environment.getDataDirectory();//5
            mAppDataDir = new File(dataDir, "data");
            mAppInstallDir = new File(dataDir, "app");
            mAppLib32InstallDir = new File(dataDir, "app-lib");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mUserAppDataDir = new File(dataDir, "user");
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
			// 创建多用户管理服务
            sUserManager = new UserManagerService(context, this,
                    mInstallLock, mPackages);

在开始阶段中创建了很多PMS中的关键对象并赋值给PMS中的成员变量,下面简单介绍这些成员变量。

mSettings :用于保存所有包的动态设置。注释1处将系统进程的sharedUserId添加到Settings中,sharedUserId用于进程间共享数据,比如两个App的之间的数据是不共享的,如果它们有了共同的sharedUserId,就可以运行在同一个进程中共享数据。

mInstallerInstaller继承自SystemService,和PMSAMS一样是系统的服务(虽然名称不像是服务),PMS很多的操作都是由Installer来完成的,比如APK的安装和卸载。在Installer内部,通过IInstalldinstalld进行Binder通信,由位于nativie层的installd来完成具体的操作。

systemConfig:用于得到全局系统配置信息。比如系统的权限就可以通过SystemConfig来获取。

mPackageDexOptimizer : Dex优化的工具类。

mHandlerPackageHandler类型) :PackageHandler继承自Handler,在注释3处它绑定了后台线程ServiceThread的消息队列。PMS通过PackageHandler驱动APK的复制和安装工作,参考前面的APK拷贝。
PackageHandler处理的消息队列如果过于繁忙,有可能导致系统卡住, 因此在注释4处将它添加到Watchdog的监测集中。
Watchdog主要有两个用途,一个是定时检测系统关键服务(AMSWMS等)是否可能发生死锁,还有一个是定时检测线程的消息队列是否长时间处于工作状态(可能阻塞等待了很长时间)。如果出现上述问题,Watchdog会将日志保存起来,必要时还会杀掉自己所在的进程,也就是SystemServer进程。

sUserManagerUserManagerService类型) :多用户管理服务。

3.4.2 扫描系统阶段
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
			...
			// 打印扫描系统阶段日志
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

			// 在/system中创建framework目录
            File frameworkDir = new File(Environment.getRootDirectory(), "framework");

            // Gross hack for now: we know this file doesn't contain any
            // code, so don't dexopt it to avoid the resulting log spew.
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");

			 //扫描/vendor/overlay目录下的文件
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

            //扫描/system/framework 目录下的文件
            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);

           //扫描 /system/priv-app 目录下的文件
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

           //扫描/system/app 目录下的文件
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            // Collect all vendor packages.
            File vendorAppDir = new File("/vendor/app");
            try {
                vendorAppDir = vendorAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
             //扫描 /vendor/app 目录下的文件
            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

           //扫描/oem/app 目录下的文件
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

              //这个列表代表有可能有升级包的系统App
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * If this is not a system app, it can't be a
                     * disable system app.
                     */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }

                  //这里的mPackages的是PMS的成员变量,代表scanDirTracedLI方法扫描上面那些目录得到的 
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) {
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            //将这个系统App的PackageSetting从PMS的mPackages中移除
                            removePackageLI(ps, true);
                              //将升级包的路径添加到mExpectingBetter列表中
                            mExpectingBetter.put(ps.name, ps.codePath);
                        }

                        continue;
                    }

                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        logCriticalInfo(Log.WARN, "System package " + ps.name
                                + " no longer exists; wiping its data");
                        removeDataDirsLI(null, ps.name);
                    } else {
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        //这个系统App升级包信息在mDisabledSysPackages中,但是没有发现这个升级包存在
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }
            ...

/system可以称作为System分区,里面主要存储谷歌和其他厂商提供的Android系统相关文件和框架。Android系统架构分为应用层、应用框架层、系统运行库层(Native 层)、硬件抽象层(HAL层)和Linux内核层,除了Linux内核层在Boot分区,其他层的代码都在System分区。下面列出 System分区的部分子目录。

目录含义
system/app存放系统App,包括了谷歌内置的App也有厂商或者运营商提供的App
system/framework存放应用框架层的jar包
system/priv-app存放特权App
system/lib存放so文件
system/fonts存放系统字体文件
system/media存放系统的各种声音,比如铃声、提示音,以及系统启动播放的动画

系统扫描阶段的主要工作有以下3点:

  1. 创建/system的子目录,比如/system/framework、/system/priv-app和/system/app等等
  2. 扫描系统文件,比如/system/framework、/system/app等等目录下的文件
  3. 对扫描到的系统文件做后续处理
3.4.3 扫描Data分区阶段
   // 打印扫描Data分区阶段日志
   EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                // 扫描/data/app目录下的文件      
                scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
			    // 扫描/data/app-private目录下的文件  
                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);
                // 扫描完Data分区后,处理possiblyDeletedUpdatedSystemApps列表
                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                    // 从mSettings.mDisabledSysPackages变量中移除去此应用
                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                    String msg;
                     //1:如果这个系统App的包信息不在PMS的变量mPackages中,说明是残留的App信息,后续会删除它的数据。
                    if (deletedPkg == null) {
                        msg = "Updated system package " + deletedAppName
                                + " no longer exists; wiping its data";
                        removeDataDirsLI(null, deletedAppName);
                    } else {
                    	//2:如果这个系统App在mPackages中,说明是存在于Data分区,不属于系统App,那么移除其系统权限。
                        msg = "Updated system app + " + deletedAppName
                                + " no longer present; removing system privileges for "
                                + deletedAppName;

                        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

                        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                    }
                    logCriticalInfo(Log.WARN, msg);
                }

                 //遍历mExpectingBetter列表
                for (int i = 0; i < mExpectingBetter.size(); i++) {
                    final String packageName = mExpectingBetter.keyAt(i);
                    if (!mPackages.containsKey(packageName)) {
                        //得到系统App的升级包路径
                        final File scanFile = mExpectingBetter.valueAt(i);

                        // 3:根据系统App所在的目录设置扫描的解析参数
                        final int reparseFlags;
                        if (FileUtils.contains(privilegedAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR
                                    | PackageParser.PARSE_IS_PRIVILEGED;
                        } else if (FileUtils.contains(systemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(vendorAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(oemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else {
                            Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                            continue;
                        }
						 //将packageName对应的包设置数据(PackageSetting)添加到mSettings的mPackages中
                        mSettings.enableSystemPackageLPw(packageName);

                        try {
                           //扫描系统App的升级包
                            scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
                        } catch (PackageManagerException e) {
                            Slog.e(TAG, "Failed to parse original system package: "
                                    + e.getMessage());
                        }
                    }
                }
            }
            mExpectingBetter.clear();

/data可以称为Data分区,它用来存储所有用户的个人数据和配置文件。下面列出Data分区部分子目录:

目录含义
data/app存储用户自己安装的App
data/data存储所有已安装的App数据的目录,每个App都有自己单独的子目录
data/app-privateApp的私有存储空间
data/app-lib存储所有App的Jni库
data/system存放系统配置文件
data/anr用于存储ANR发生时系统生成的traces.txt文件
3.4.4 扫描结束阶段
//  打印扫描结束阶段日志
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");

 // 如果当前平台SDK版本和上次启动时的SDK版本不同,重新更新APK的授权
            int updateFlags = UPDATE_PERMISSIONS_ALL;
            if (ver.sdkVersion != mSdkVersion) {
                Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
                        + mSdkVersion + "; regranting permissions for internal storage");
                updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
            }
            updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
            ver.sdkVersion = mSdkVersion;

           //如果是第一次启动,需要初始化所有用户定义的默认首选App
            if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
                for (UserInfo user : sUserManager.getUsers(true)) {
                    mSettings.applyDefaultPreferredAppsLPw(this, user.id);
                    applyFactoryDefaultBrowserLPw(user.id);
                    primeDomainVerificationsLPw(user.id);
                }
            }

             //OTA后的第一次启动,会清除代码缓存目录。
            if (mIsUpgrade && !onlyCore) {
                Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                for (int i = 0; i < mSettings.mPackages.size(); i++) {
                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
                    if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                        deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
            }

            checkDefaultBrowser();

            // clear only after permissions and other defaults have been updated
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;

            // All the changes are done during package scanning.
            ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

            // 把Settings的内容保存到packages.xml中
            mSettings.writeLPr();

扫描结束结束阶段主要做了以下几件事:

  1. 如果当前平台SDK版本和上次启动时的SDK版本不同,重新更新APK的授权。
  2. 如果是第一次启动,需要初始化所有用户定义的默认首选App。
  3. OTA升级后的第一次启动,会清除代码缓存目录。
  4. 把Settings的内容保存到packages.xml中,这样此后PMS再次创建时会读到此前保存的Settings的内容。
3.4.5 准备阶段
  EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            mRequiredVerifierPackage = getRequiredVerifierLPr();
            mRequiredInstallerPackage = getRequiredInstallerLPr();

            mInstallerService = new PackageInstallerService(context, this);//1

            mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
            mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                    mIntentFilterVerifierComponent);
                     } // synchronized (mPackages)
        } // synchronized (mInstallLock)

        // Now after opening every single application zip, make sure they
        // are all flushed.  Not really needed, but keeps things nice and
        // tidy.
        Runtime.getRuntime().gc();

        // Expose private service for system components to use.
        LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());//2

注释1处创建PackageInstallerServicePackageInstallerService是用于管理安装会话的服务,它会为每次安装过程分配一个SessionId
注释2处将PackageManagerInternalImplPackageManager的本地服务)添加到LocalServices中,LocalServices用于存储运行在当前的进程中的本地服务。

3.5 PMS解析APK

3.5.1 PackageParser引入

Android世界中有很多包,比如应用程序的APK,Android运行环境的JAR包(比如framework.jar)和组成Android系统的各种动态库so等等,由于包的种类和数量繁多,就需要进行包管理,但是包管理需要在内存中进行,而这些包都是以静态文件的形式存在的,就需要一个工具类将这些包转换为内存中的数据结构,这个工具就是包解析器PackageParser

再看下 前面的installPackageLI代码:

    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
         ...
        PackageParser pp = new PackageParser();//1
        final PackageParser.Package pkg;
        try {
            // 1.创建PackageParser解析APK
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);//2
        } catch (PackageParserException e) {
            res.setError("Failed parse during installPackageLI", e);
            return;
        }

可以看到安装APK时,需要先在注释1处创建PackageParser,然后在注释2处调用PackageParserparsePackage方法来解析APK。

3.5.2 PackageParser解析APK

Android5.0引入了Split APK机制,这是为了解决65536上限以及APK安装包越来越大等问题。Split APK机制可以将一个APK,拆分成多个独立APK。
在引入了Split APK机制后,APK有两种分类:

  1. Single APK:安装文件为一个完整的APK,即base APK。Android称其为Monolithic
  2. Mutiple APK:安装文件在一个文件目录中,其内部有多个被拆分的APK,这些APK由一个 base APK和一个或多个split APK组成。Android称其为Cluster

===>先看 pp.parsePackage方法的实现,结合前面的分类,可以知道,如果要解析的packageFile是一个目录,说明是Mutiple APK,就需要调用parseClusterPackage方法来解析,如果是Single APK则调用parseMonolithicPackage方法来解析,代码如下:

    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(packageFile, flags);
        } else {
            return parseMonolithicPackage(packageFile, flags);
        }
    }

===>以相对复杂的parseClusterPackage继续分析,代码如下:

    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
        final PackageLite lite = parseClusterPackageLite(packageDir, 0);//1

        if (mOnlyCoreApps && !lite.coreApp) {//2
            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                    "Not a coreApp: " + packageDir);
        }

        final AssetManager assets = new AssetManager();
        try {
           // 把base和所有split都加入assets
            loadApkIntoAssetManager(assets, lite.baseCodePath, flags);

            if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
                for (String path : lite.splitCodePaths) {
                    loadApkIntoAssetManager(assets, path, flags);
                }
            }

            final File baseApk = new File(lite.baseCodePath);
            final Package pkg = parseBaseApk(baseApk, assets, flags);//3
            if (pkg == null) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                        "Failed to parse base APK: " + baseApk);
            }

            if (!ArrayUtils.isEmpty(lite.splitNames)) {
                final int num = lite.splitNames.length;//4
                pkg.splitNames = lite.splitNames;
                pkg.splitCodePaths = lite.splitCodePaths;
                pkg.splitRevisionCodes = lite.splitRevisionCodes;
                pkg.splitFlags = new int[num];
                pkg.splitPrivateFlags = new int[num];

                for (int i = 0; i < num; i++) {
                    parseSplitApk(pkg, i, assets, flags);//5
                }
            }

            pkg.codePath = packageDir.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

注释1处调用parseClusterPackageLite方法用于轻量级解析目录文件,之所以要轻量级解析是因为解析APK是一个复杂耗时的操作,这里的逻辑并不需要APK所有的信息。parseClusterPackageLite方法内部会通过parseApkLite方法解析每个Mutiple APK,得到每个Mutiple APK对应的ApkLite(轻量级APK信息),然后再将这些ApkLite封装为一个PackageLite(轻量级包信息)并返回。

注释2处,mOnlyCoreApps用来指示PackageParser是否只解析“核心”应用,“核心”应用指的是AndroidManifest中属性coreApp值为true,只解析“核心”应用是为了创建一个极简的启动环境。mOnlyCoreApps在创建PMS时就一路传递过来,如果我们加密了设备,mOnlyCoreApps值就为true

注释3处的parseBaseApk方法用于解析base APK,注释4处获取split APK的数量,根据这个数量在注释5处遍历调用parseSplitApk来解析每个split APK

===>先来看下parseClusterPackageLite方法,它的调用流程如下:

    private static PackageLite parseClusterPackageLite(File packageDir, int flags)
            throws PackageParserException {
      	....
        final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
        for (File file : files) {
            if (isApkFile(file)) {
                final ApkLite lite = parseApkLite(file, flags);
                ...
    }
    --->ApkLite 的实现:
        public static class ApkLite {
        public final String codePath;
        public final String packageName;
        public final String splitName;
        public final int versionCode;
        public final int revisionCode;
        public final int installLocation;
        public final VerifierInfo[] verifiers;
        public final Signature[] signatures;
        public final boolean coreApp;
        public final boolean multiArch;
        public final boolean extractNativeLibs;

===>再来看下parseBaseApk方法,它的调用流程如下:

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;
        if (apkPath.startsWith(MNT_EXPAND)) {
            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);//1
        }

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkFile.getAbsolutePath();

        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);

        Resources res = null;
        XmlResourceParser parser = null;
        try {
            res = new Resources(assets, mMetrics, null);
            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    Build.VERSION.RESOURCES_SDK_INT);
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];
            final Package pkg = parseBaseApk(res, parser, flags, outError);//2
            if (pkg == null) {
                throw new PackageParserException(mParseError,
                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
            }

            pkg.volumeUuid = volumeUuid; // 3 
            pkg.applicationInfo.volumeUuid = volumeUuid; // 4
            pkg.baseCodePath = apkPath;
            pkg.mSignatures = null;

            return pkg;

        } catch (PackageParserException e) {
            throw e;
        } catch (Exception e) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to read manifest from " + apkPath, e);
        } finally {
            IoUtils.closeQuietly(parser);
        }
    }
---->

注释1处,如果APK的路径以/mnt/expand/开头,就截取该路径获取volumeUuid
注释3处用于以后标识这个解析后的Package
注释4处的用于标识该App所在的存储卷UUID
注释2处又调用了parseBaseApk的重载方法,可以看出当前的parseBaseApk方法主要是为了获取和设置volumeUuid

===>继续看下parseBaseApk重载方法,它的调用流程如下:

  1. 创建Package对象
  2. 从资源中提取自定义属性集com.android.internal.R.styleable.AndroidManifest得到TypedArray ,并赋值给pkg
  3. 读取APK的AndroidManifest中的coreApp的值
  4. 用来解析APK的AndroidManifest中的各个标签,比如applicationpermissionuses-sdkfeature-group

解析application标签的方法为parseBaseApplication,有近500行代码,而Application只是AndroidManifest众多标签的一个,这让我们更加理解了为什么此前解析APK时要使用轻量级解析了,parseBaseApk方法主要的解析结构可以理解为以下简图。
在这里插入图片描述
代码如下:

  private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
         ...
     	// 1.创建Package对象
        final Package pkg = new Package(pkgName);
        boolean foundApp = false;
		// 2.从资源中提取自定义属性集com.android.internal.R.styleable.AndroidManifest得到TypedArray 
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifest);
        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
        pkg.baseRevisionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
       
        ...
        // 3.读取APK的AndroidManifest中的coreApp的值
        pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);
		 //获取资源后要回收
        sa.recycle();

        /* Set the global "forward lock" flag */
        if ((flags & PARSE_FORWARD_LOCK) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
        }

        /* Set the global "on SD card" flag */
        if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
        }

        // Resource boolean are -1, so 1 means we don't know the value.
        int supportsSmallScreens = 1;
        int supportsNormalScreens = 1;
        int supportsLargeScreens = 1;
        int supportsXLargeScreens = 1;
        int resizeable = 1;
        int anyDensity = 1;
        
        int outerDepth = parser.getDepth();
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("application")) {
                 ...

                foundApp = true;
                if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) { // 3
                    return null;
                }
            } else if (tagName.equals("overlay")) {
                pkg.mTrustedOverlay = trustedOverlay;

                sa = res.obtainAttributes(attrs,
                        com.android.internal.R.styleable.AndroidManifestResourceOverlay);
                pkg.mOverlayTarget = sa.getString(
                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
                pkg.mOverlayPriority = sa.getInt(
                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
                        -1);
                sa.recycle();

                if (pkg.mOverlayTarget == null) {
                    outError[0] = "<overlay> does not specify a target package";
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return null;
                }
                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
                    outError[0] = "<overlay> priority must be between 0 and 9999";
                    mParseError =
                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return null;
                }
                XmlUtils.skipCurrentTag(parser);

            } else if (tagName.equals("key-sets")) {
              // 4.各种解析tagname....
              .....
		
        }

        if (!foundApp && pkg.instrumentation.size() == 0) {
            outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
        }

        final int NP = PackageParser.NEW_PERMISSIONS.length;
        StringBuilder implicitPerms = null;
        for (int ip=0; ip<NP; ip++) {
            final PackageParser.NewPermissionInfo npi
                    = PackageParser.NEW_PERMISSIONS[ip];
            if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
                break;
            }
            if (!pkg.requestedPermissions.contains(npi.name)) {
                if (implicitPerms == null) {
                    implicitPerms = new StringBuilder(128);
                    implicitPerms.append(pkg.packageName);
                    implicitPerms.append(": compat added ");
                } else {
                    implicitPerms.append(' ');
                }
                implicitPerms.append(npi.name);
                pkg.requestedPermissions.add(npi.name);
            }
        }
        if (implicitPerms != null) {
            Slog.i(TAG, implicitPerms.toString());
        }

        final int NS = PackageParser.SPLIT_PERMISSIONS.length;
        for (int is=0; is<NS; is++) {
            final PackageParser.SplitPermissionInfo spi
                    = PackageParser.SPLIT_PERMISSIONS[is];
            if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
                    || !pkg.requestedPermissions.contains(spi.rootPerm)) {
                continue;
            }
            for (int in=0; in<spi.newPerms.length; in++) {
                final String perm = spi.newPerms[in];
                if (!pkg.requestedPermissions.contains(perm)) {
                    pkg.requestedPermissions.add(perm);
                }
            }
        }

        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
                && pkg.applicationInfo.targetSdkVersion
                        >= android.os.Build.VERSION_CODES.DONUT)) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
        }
        if (supportsNormalScreens != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
        }
        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
                && pkg.applicationInfo.targetSdkVersion
                        >= android.os.Build.VERSION_CODES.DONUT)) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
        }
        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
                && pkg.applicationInfo.targetSdkVersion
                        >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
        }
        if (resizeable < 0 || (resizeable > 0
                && pkg.applicationInfo.targetSdkVersion
                        >= android.os.Build.VERSION_CODES.DONUT)) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
        }
        if (anyDensity < 0 || (anyDensity > 0
                && pkg.applicationInfo.targetSdkVersion
                        >= android.os.Build.VERSION_CODES.DONUT)) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
        }

        return pkg;
    }

包被解析后,最终在内存是PackagePackagePackageParser的内部类,它的部分成员变量如下所示。

    /**
     * Representation of a full package parsed from APK files on disk. A package
     * consists of a single base APK, and zero or more split APKs.
     */
    public final static class Package {

        public String packageName; // 包名

        /** Names of any split APKs, ordered by parsed splitName */
        public String[] splitNames;

        // TODO: work towards making these paths invariant

        public String volumeUuid;

        /**
         * Path where this package was found on disk. For monolithic packages
         * this is path to single base APK file; for cluster packages this is
         * path to the cluster directory.
         */
        public String codePath;

        /** Path of base APK */
        public String baseCodePath;
        /** Paths of any split APKs, ordered by parsed splitName */
        public String[] splitCodePaths;

        /** Revision code of base APK */
        public int baseRevisionCode;
        /** Revision codes of any split APKs, ordered by parsed splitName */
        public int[] splitRevisionCodes;

        /** Flags of any split APKs; ordered by parsed splitName */
        public int[] splitFlags;

        /**
         * Private flags of any split APKs; ordered by parsed splitName.
         *
         * {@hide}
         */
        public int[] splitPrivateFlags;

        public boolean baseHardwareAccelerated;

        // For now we only support one application per package.
        public final ApplicationInfo applicationInfo = new ApplicationInfo();

		//4 大组件
        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
        public final ArrayList<Service> services = new ArrayList<Service>(0);
        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);

        public final ArrayList<String> requestedPermissions = new ArrayList<String>();

        public ArrayList<String> protectedBroadcasts;

        public ArrayList<String> libraryNames = null;
        public ArrayList<String> usesLibraries = null;
        public ArrayList<String> usesOptionalLibraries = null;
        public String[] usesLibraryFiles = null;

        public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;

        public ArrayList<String> mOriginalPackages = null;
        public String mRealPackage = null;
        public ArrayList<String> mAdoptPermissions = null;
        
        // We store the application meta-data independently to avoid multiple unwanted references
        public Bundle mAppMetaData = null;

        // The version code declared for this package.
        public int mVersionCode;

        // The version name declared for this package.
        public String mVersionName;
        
        // The shared user id that this package wants to use.
        public String mSharedUserId;

        // The shared user label that this package wants to use.
        public int mSharedUserLabel;

        // Signatures that were read from the package.
        public Signature[] mSignatures;
        public Certificate[][] mCertificates;

        // For use by package manager service for quick lookup of
        // preferred up order.
        public int mPreferredOrder = 0;

        // For use by package manager to keep track of where it needs to do dexopt.
        public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);

        // For use by package manager to keep track of when a package was last used.
        public long mLastPackageUsageTimeInMills;

        // // User set enabled state.
        // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
        //
        // // Whether the package has been stopped.
        // public boolean mSetStopped = false;

        // Additional data supplied by callers.
        public Object mExtras;

        // Applications hardware preferences
        public ArrayList<ConfigurationInfo> configPreferences = null;

        // Applications requested features
        public ArrayList<FeatureInfo> reqFeatures = null;

        // Applications requested feature groups
        public ArrayList<FeatureGroupInfo> featureGroups = null;

        public int installLocation;

        public boolean coreApp;

        /* An app that's required for all users and cannot be uninstalled for a user */
        public boolean mRequiredForAllUsers;

        /* The restricted account authenticator type that is used by this application */
        public String mRestrictedAccountType;

        /* The required account type without which this application will not function */
        public String mRequiredAccountType;

        /**
         * Digest suitable for comparing whether this package's manifest is the
         * same as another.
         */
        public ManifestDigest manifestDigest;

        public String mOverlayTarget;
        public int mOverlayPriority;
        public boolean mTrustedOverlay;

        /**
         * Data used to feed the KeySetManagerService
         */
        public ArraySet<PublicKey> mSigningKeys;
        public ArraySet<String> mUpgradeKeySets;
        public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;

注意4大组件那里,ActivityProviderService都是PackageParser的静态内部类,例如Activity

  public final static class Activity extends Component<ActivityIntentInfo> {
        public final ActivityInfo info;

        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
            super(args, _info);
            info = _info;
            info.applicationInfo = args.owner.applicationInfo;
        }
        
        public void setPackageName(String packageName) {
            super.setPackageName(packageName);
            info.packageName = packageName;
        }

        public String toString() {
            StringBuilder sb = new StringBuilder(128);
            sb.append("Activity{");
            sb.append(Integer.toHexString(System.identityHashCode(this)));
            sb.append(' ');
            appendComponentShortName(sb);
            sb.append('}');
            return sb.toString();
        }
    }

Package简图如下:
在这里插入图片描述
从这个简图中可以发现Package的数据结构是如何设计的:

  1. Package中存有许多组件,比如ActicityProviderPermission等等,它们都继承基类Component
  2. 每个组件都包含一个info数据,比如Activity类中包含了成员变量ActivityInfo,这个ActivityInfo才是真正的Activity数据。
  3. 四大组件的标签内可能包含<intent-filter>来过滤Intent信息,因此需要IntentInfo来保存组件的intent信息,组件基类Component依赖于IntentInfo
    public static class Component<II extends IntentInfo> {
        public final Package owner;
        public final ArrayList<II> intents;
        public final String className;
        public Bundle metaData;

        ComponentName componentName;
        String componentShortName;
--->IntentInfo的代码如下:
    public static class IntentInfo extends IntentFilter {
        public boolean hasDefault;
        public int labelRes;
        public CharSequence nonLocalizedLabel;
        public int icon;
        public int logo;
        public int banner;
        public int preferred;
    }
--->IntentFilter的代码如下:
public class IntentFilter implements Parcelable {
...
  public static final String SCHEME_HTTPS = "https";

    private int mPriority;
    private final ArrayList<String> mActions;
    private ArrayList<String> mCategories = null;
    private ArrayList<String> mDataSchemes = null;
    private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
    private ArrayList<AuthorityEntry> mDataAuthorities = null;
    private ArrayList<PatternMatcher> mDataPaths = null;
    private ArrayList<String> mDataTypes = null;
    private boolean mHasPartialTypes = false;
}

IntentInfo有三个子类ActivityIntentInfoServiceIntentInfoProviderIntentInfo,不同组件依赖的IntentInfo会有所不同,如下:

public final class Activity extends Component<ActivityIntentInfo>
public final static class Service extends Component<ServiceIntentInfo> 
public final static class Provider extends Component<ProviderIntentInfo>

4.VirtualApp中PMS的实现

VirtualApp中解析后的数据都保存在PackageParser类中,由PackageParserExPackageParserEx扩展了PackageParser)解析,对外的数据是VPackage

4.1 PackageParser类简介

VA自建的android.content.pm.PackageParse,它其实更多的意义是占位类,让反射方式更优雅,它和系统的android.content.pm.PackageParse保持一致,但实际上,系统解析得到的android.content.pm.PackageParse,还是系统那一份。
PackageParser类最底层数据仍是IntentInfo,如下:

    public static class IntentInfo extends IntentFilter { 
        public boolean hasDefault;
        public int labelRes;
        public CharSequence nonLocalizedLabel;
        public int icon;
        public int logo;
        public int banner;
    }

同样有一个Component基类,如下:

    public static class Component<II extends IntentInfo> {
        public Package owner;
        public ArrayList<II> intents;
        public String className;
        public Bundle metaData;

        public ComponentName getComponentName() {
            return null;
        }
    }

getComponentName代替了 ComponentName componentName;
前面提到Package中存有许多组件,比如ActicityProviderPermission等等,它们都继承基类Component,另外前面提到Package中每个组件都包含一个info数据,info数据才是真正的数据,VA采用了同样的构造方式,如下:

    public final static class Activity extends Component<ActivityIntentInfo> {
        public ActivityInfo info; 
    }
    
    public class ActivityIntentInfo extends IntentInfo {
        public Activity activity;
    }

对比系统的,完全一致:

    public final static class Activity extends Component<ActivityIntentInfo> {
        public final ActivityInfo info;
        ...
        }
public final static class ActivityIntentInfo extends IntentInfo {
        public final Activity activity;
        ...

对应Package类也 相对砍掉了不少变量,其中SigningDetailsAPI28才增加的新变量

    public class Package {
        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
        public final ArrayList<Service> services = new ArrayList<Service>(0);
        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
        public final ArrayList<String> requestedPermissions = new ArrayList<String>();
        public Signature[] mSignatures;
        public SigningDetails mSigningDetails; // API 28
        public Bundle mAppMetaData;
        public Object mExtras;
        public String packageName;
        public int mPreferredOrder;
        public String mSharedUserId;
        public ArrayList<String> usesLibraries;
        public int mVersionCode;
        public ApplicationInfo applicationInfo;
        public String mVersionName;

        // Applications hardware preferences
        public ArrayList<ConfigurationInfo> configPreferences = null;

        // Applications requested features
        public ArrayList<FeatureInfo> reqFeatures = null;
        public int mSharedUserLabel;
    }

PackageParse类没有解析函数,保存一些仿系统的数据类的简化版,对应的Parcelable实现为VPackage
解析代码位于PackageParserEx
PackageParse类位于android.content.pm,这和系统保持一致

4.2 VPackage类简介

PackageParse类对应的Parcelable实现为VPackage类,
比如PackageParse.IntentInfo对应VPackage.IntentInfo,VPackage.IntentInfo提供了相应的构造函数进行转换

  public static class IntentInfo implements Parcelable {
  		...
  		public IntentInfo(PackageParser.IntentInfo info) {
            this.filter = info;
            this.hasDefault = info.hasDefault;
            this.labelRes = info.labelRes;
            if (info.nonLocalizedLabel != null) {
                this.nonLocalizedLabel = info.nonLocalizedLabel.toString();
            }
            this.icon = info.icon;
            this.logo = info.logo;
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
                this.banner = info.banner;
            }
        }
  }

同样的,PackageParse.Component对应VPackage.ComponentVPackage.Component提供了相应的构造函数进行转换

        public Component(PackageParser.Component component) {
            this.className = component.className;
            this.metaData = component.metaData;
        }

同理,一一对应,VPackage均提供了相应的构造函数进行转换
PackageParse.ActivityIntentInfo对应VPackage.ActivityIntentInfo
PackageParse.ServiceIntentInfo对应VPackage.ServiceIntentInfo
PackageParse.ProviderIntentInfo对应VPackage.ProviderIntentInfo
PackageParse.Activity对应VPackage.ActivityComponent
PackageParse.Service对应VPackage.ServiceComponent
PackageParse.Provider对应VPackage.ProviderComponent
PackageParse.Instrumentation对应VPackage.InstrumentationComponent
PackageParse.Permission对应VPackage.PermissionComponent
PackageParse.PermissionGroup对应VPackage.PermissionGroupComponent

4.3 PackageParserEx类简介

PackageParserEx继承于PackageParse类,类似于系统的PackageParse类,它提供了parsePackage接口,这个函数第一行是:

   PackageParser parser = PackageParserCompat.createParser(packageFile);

VA自建的android.content.pm.PackageParse,它其实更多的意义是占位符,让反射方式更优雅,它和系统的android.content.pm.PackageParse保持一致,但实际上,系统解析得到的android.content.pm.PackageParse,所以这里返回的还是系统的那一份PackageParser ,不要理解为VA的那一份

PackageParserCompat是一个包装类,内部通过区分APK版本号来反射系统的android.content.pm.PackageParse
parsePackage代码如下:

public static VPackage parsePackage(File packageFile) throws Throwable { // 59
        PackageParser parser = PackageParserCompat.createParser(packageFile);
        PackageParser.Package p = PackageParserCompat.parsePackage(parser, packageFile, 0);
        ...
        return buildPackageCache(p);
    }
 -->PackageParserCompat.createParser代码如下:
   public static PackageParser createParser(File packageFile) {
        if (API_LEVEL >= M) {
            return PackageParserMarshmallow.ctor.newInstance();
         ...

占位类的好处是可以直接调用系统隐藏类的变量,不能再通过反射方式去获取了, 如下图:
在这里插入图片描述
buildPackageCache方法用于把将系统的Package.Package转换成可以序列化的 VPackage 类型

4.4 VAMS中安装包的详细实现流程

VAMS中安装包的函数是installPackageImpl,以下是全流程跟进:

假定我们的安装包路径是:/data/app/com.hgy413.refclass-xxx==/base.apk

===> 1.利用PackageParserEx.parsePackage(packageFile);base.apk解析成 VPackage pkg
内部仍是利用系统的android.content.pm.PackageParser解包成PackageParser.Package
虽然我们定义了一个PackageParser,但它的作用就是简单的避免反射调用系统的android.content.pm.PackageParser

   PackageParser.Package p = PackageParserCompat.parsePackage(parser, packageFile, 0);

然后通过buildPackageCachePackageParser.Package转成 VPackage pkg
最后通过addOwnerVPackage.ActivityComponent, VPackage.ServiceComponent等的owner设置为 VPackage pkg自身。
如果是google service,还需要加上 flags |= ApplicationInfo.FLAG_PERSISTENT;

===> 2.判断是否需要升级
PackageCacheManager类:
它的成员 ArrayMap<String, VPackage> PACKAGE_CACHE记录了所有的 VPackagekey为包名。
VPackagemExtras成员变量中又记录了PackageSetting对象,所以PackageSetting对象和 VPackage就关联起来了。

升级逻辑如下:
首先去PackageCacheManager类中查找是否已存在相同包名的 VPackage,不存在就继续 。

如果存在,检查传入的InstallOptions.updateStrategy值,默认是COMPARE_VERSION,也就是比较新旧安装包的versioncode,仅当新的>旧的才覆盖安装。

如果需要升级,就要调用VActivityManagerService.get().killAppByPkg把原来的进程kill掉,并从PACKAGE_CACHE中移除原来的VPackage。如果不需要升级,就直接返回升级失败。

===> 3.初始化PackageSetting ps对象
如果PACKAGE_CACHE中已存在VPackage,就取VPackagemExtras成员变量,否则创建一个新的PackageSetting ps对象。

===> 4.复制abi下的so文件到virtual目录

  1. NativeLibraryHelperCompat.getSupportAbiList通过zip解压遍历base.apk得到它内部有哪些abi,也就是base.apklib目录下有哪些abi,如armeabi-v7ax86等。

  2. 如果abiarm64-v8ax86_64mips64中一个目录,就认为这个apk支持x64, 这种属性通过PackageSetting ps.flag来记录

if (support32bit) {
            if (support64bit) {
                ps.flag = PackageSetting.FLAG_RUN_BOTH_32BIT_64BIT;
            } else {
                ps.flag = PackageSetting.FLAG_RUN_32BIT;
            }
        } else {
            ps.flag = PackageSetting.FLAG_RUN_64BIT;
        }
  1. NativeLibraryHelperCompat.copyNativeBinaries执行复制abi操作,例如把/data/app/com.hgy413.refclass-xxx==/base.apk中的lib/x86/libv++.so拷贝到/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/libv++.so,系统安装apk时,系统会把abi解压到data/app/com.hgy.ndk/lib, VA以类似的方式保存在它的virtual目录中, 差别是它把x86这个abi目录去掉了。

  2. 默认如果是系统安装过的apk,则useSourceLocationApk=true, 这时使用外部的apk。
    但如果是未被安装的apk安装包,则useSourceLocationApk=false, 这时需要做apk拷贝。
    例如:把/data/app/com.hgy413.refclass-xxx==/base.apk拷贝到/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/base.apk,并把packageFile指向拷贝后的目录。

===> 5.设置PackageSetting ps对象
设置以下信息到ps中,在前面还设置了ps.flag

 ps.appMode = useSourceLocationApk ? MODE_APP_USE_OUTSIDE_APK : MODE_APP_COPY_APK;
 ps.packageName = pkg.packageName;
 ps.appId = VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg));
  if (res.isUpdate) {
            ps.lastUpdateTime = installTime;
        } else {
            ps.firstInstallTime = installTime;
            ps.lastUpdateTime = installTime;
            for (int userId : VUserManagerService.get().getUserIds()) {
                boolean installed = userId == 0;// 默认用户 userId = 0时,installed为true
                ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed);
            }
        }
  ---> ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed);
  public class PackageUserState implements Parcelable {
    public boolean launched;
    public boolean hidden;
    public boolean installed;
  }

VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg));仿系统的UMS机制,默认appid10001开始,依次递增。
ps.setUserState内部会针对每个用户环璋生成一个PackageUserState,并记录这个ps在每个用户环境的安装状态。
默认用户环境(userid=0)是launched = false, hidden = false, installed = true;, 其余用户环境是launched = false, hidden = false, installed = false;

简单的说,PackageSetting记录了安装时间,更新时间,每个用户环境的安装状态,包名,appid, 是否拷贝了apk, 是否支持x64,等信息。

===> 6.把VPackage pkg写入package.inisignature.ini文件
PackageParserEx.savePackageCache(pkg);所做的操作:

  1. 先获取virtual/data/app/packageName/package.ini,以及virtual/data/app/packageName/signature.ini
  2. Parcel方式把pkg写入到package.ini中:(在loadPackageInnerLocked中会跨进程从package.ini读取pkg)
            pkg.writeToParcel(p, 0);
            FileOutputStream fos = new FileOutputStream(cacheFile);
            fos.write(p.marshall());
            fos.close();
  1. Parcel方式把pkg.mSignatures写入到signature.ini

===> 7.把VPackage pkgPackageSetting ps都存在PackageCacheManager

 PackageParserEx.initApplicationInfoBase(ps, pkg);
 PACKAGE_CACHE.put(pkg.packageName, pkg); // 存入`VPackage pkg`
 pkg.mExtras = ps; // 存入`PackageSetting ps`
 VPackageManagerService.get().analyzePackageLocked(pkg);

PackageParserEx.initApplicationInfoBase(ps, pkg);就是把pkg.ApplicationInfo根据ps做一些初始化,如uid,sharedLibraryFiles

===> 8. 接第7点的VPackageManagerService.get().analyzePackageLocked(pkg)继续分析:
主要是VPMS保存VPackage pkg的一些信息

  1. 保存pkg的activitiesmActivities
    mActivities的类型是ActivityIntentResolver,它内部的addActivity函数如下:
 public final void addActivity(VPackage.ActivityComponent a, String type) {
            mActivities.put(a.getComponentName(), a);
            final int NI = a.intents.size();
            for (int j = 0; j < NI; j++) {
                VPackage.ActivityIntentInfo intent = a.intents.get(j);
                if (intent.filter.getPriority() > 0 && "activity".equals(type)) {
                    intent.filter.setPriority(0);
                    Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity " + a.className
                            + " with priority > 0, forcing to 0");
                }
                addFilter(intent);
            }
        }

ComponentName类由packageNameclassName组成,例如:mClass = com.hgy.ndk.MainActivity, mPackage = com.hgy.ndk

所有的activity都被ActivityIntentResolver记录到它的mActivities中,keyComponentName:
HashMap<ComponentName, VPackage.ActivityComponent> mActivities

所有的intent都被ActivityIntentResolver记录到它的mFilters中:
private HashSet<F> mFilters = new HashSet<F>();

同时intent也会被解析出action之类的字符串加入到内部mActionToFilter, schemes字符串加入到内部mSchemeToFilter

以获取action字符串为例:

VPackage.ActivityComponent a
--->取第1个测试下:
VPackage.ActivityIntentInfo intent = a.intents.get(0);
--->
Iterator<String> i = f.filter.actionsIterator()
--->遍历Iterator<String> i,就可以得到android.intent.action.MAIN这种字符串了,加入mActionToFilter:
register_intent_filter(f, f.filter.actionsIterator(), mActionToFilter, "      Action: ");

在这里插入图片描述

这部分代码具体参考了系统的PackageManagerService.ActivityIntentResolver

  1. 保存pkg的servicesmServices
    这部分和1非常类似,mServices的类型是ServiceIntentResolver,它内部的addService函数如下:
        public final void addService(VPackage.ServiceComponent s) {
            mServices.put(s.getComponentName(), s);
            final int NI = s.intents.size();
            int j;
            for (j = 0; j < NI; j++) {
                VPackage.ServiceIntentInfo intent = s.intents.get(j);
                addFilter(intent);
            }
        }
  1. 保存pkg的receiversmReceivers
    mReceivers的类型同样是ActivityIntentResolver,所以它和1唯一的区别是传入的type是"receiver"
 mReceivers.addActivity(a, "receiver");
  1. 保存pkg的providersmProviders
        N = pkg.providers.size();
        for (int i = 0; i < N; i++) {
            VPackage.ProviderComponent p = pkg.providers.get(i);
            if (p.info.processName == null) {
                p.info.processName = p.info.packageName;
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                mProviders.addProvider(p);
            }
            String names[] = p.info.authority.split(";");
            synchronized (mProvidersByAuthority) {
                for (String name : names) {
                    if (!mProvidersByAuthority.containsKey(name)) {
                        mProvidersByAuthority.put(name, p);
                    }
                }
            }
            mProvidersByComponent.put(p.getComponentName(), p);
        }

mProviders的类型是ProviderIntentResolvermProviders.addProvider(p);这部分和1非常类似。
另外它要取得authority保存到mProvidersByAuthority中,它也会保存到mProvidersByComponent中,这是为了方便通过authorityComponentName快速查询到 VPackage.ProviderComponent

  1. 保存pkg的permissionsmPermissionspermissionGroupsmPermissionGroups,例如:
<permission
        android:name="android.permission.SAFE_ACCESS"
        android:protectionLevel="signature" />

下面的permission.info.name对应就是android.permission.SAFE_ACCESS,代码如下:

        N = pkg.permissions.size();
        for (int i = 0; i < N; i++) {
            VPackage.PermissionComponent permission = pkg.permissions.get(i);
            mPermissions.put(permission.info.name, permission);
        }
        N = pkg.permissionGroups.size();
        for (int i = 0; i < N; i++) {
            VPackage.PermissionGroupComponent group = pkg.permissionGroups.get(i);
            mPermissionGroups.put(group.className, group);
        }
  1. 保存pkg的requestedPermissions中的危险权限到mDangerousPermissions,例如:
<uses-permission android:name="android.permission.WRITE_SOCIAL_STREAM" />
 <uses-permission android:name="android.permission.READ_SOCIAL_STREAM" />

这里会通过PermissionCompat.findDangerousPermissions来确认请求的是否为危险权限,如果是,则加入mDangerousPermissions中,危险权限包含了这些:

public static Set<String> DANGEROUS_PERMISSION = new HashSet<String>() {{
        // CALENDAR group
        add(Manifest.permission.READ_CALENDAR);
        add(Manifest.permission.WRITE_CALENDAR);

        // CAMERA
        add(Manifest.permission.CAMERA);

        // CONTACTS
        add(Manifest.permission.READ_CONTACTS);
        add(Manifest.permission.WRITE_CONTACTS);
        add(Manifest.permission.GET_ACCOUNTS);

        // LOCATION
        add(Manifest.permission.ACCESS_FINE_LOCATION);
        add(Manifest.permission.ACCESS_COARSE_LOCATION);

        // PHONE
        add(Manifest.permission.READ_PHONE_STATE);
        add(Manifest.permission.CALL_PHONE);
        if (Build.VERSION.SDK_INT >= 16) {
            add(Manifest.permission.READ_CALL_LOG);
            add(Manifest.permission.WRITE_CALL_LOG);
        }
        add(Manifest.permission.ADD_VOICEMAIL);
        add(Manifest.permission.USE_SIP);
        add(Manifest.permission.PROCESS_OUTGOING_CALLS);

        // SMS
        add(Manifest.permission.SEND_SMS);
        add(Manifest.permission.RECEIVE_SMS);
        add(Manifest.permission.READ_SMS);
        add(Manifest.permission.RECEIVE_WAP_PUSH);
        add(Manifest.permission.RECEIVE_MMS);

        add(Manifest.permission.RECORD_AUDIO);
        // STORAGE
        add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (Build.VERSION.SDK_INT >= 16) {
            add(Manifest.permission.READ_EXTERNAL_STORAGE);
        }
        if (Build.VERSION.SDK_INT >= 20) {
            // SENSORS
            add(Manifest.permission.BODY_SENSORS);
        }
    }};

<uses-permission>是官方定义的权限,是调用别人的东西的时候自己需要声明的权限,<permission>是自己定义的权限,就是别人调用这个程序时需要用<uses-permission>来声明。

===> 9. 把PackageCacheManager的内容写入到文件packages.ini
前面提到了PackageCacheManager类包含了所有的VPackagePackageSetting数据,所以这里以Parcel写文件的方式把PackageCacheManager类保存到virtual/data/app/system/packages.ini中。

后续会在VDeviceManagerService中读取它们。

===> 10. 如果是支持32位又未被系统安装的apk(即sd卡下的apk安装包),尝试把apk解析成dex,并动态加载dex。

 if (support32bit && !useSourceLocationApk) {
       DexOptimizer.optimizeDex(packageFile.getPath(), VEnvironment.getOdexFile(ps.packageName).getPath());
}

/data/app/com.hgy413.refclass-xxx==/base.apk为例,主体逻辑如下:

  1. DexOptimizer.optimizeDex传入参数分别为/data/app/com.hgy413.refclass-xxx==/base.apk/data/data/io.busniess.va/virtual/opt/data@app@com.hgy.ndk-1@base.apk@classes.dex

  2. 判断是否为art,并且在android5.0-androi7.1之间,如果是,则调用 DexOptimizer.interpretDex2OatinterpretDex2Oat这个函数内部是调用了系统的dex2oatcmd命令来生成oat的,它被广泛使用,如微信的tinker。

  3. 调用DexFile.loadDex(dexFilePath, optFilePath, 0)

===> 11. 是否通知安装完成。
默认在AppRepository.addVirtualApp中初始化InstallOptionsnotify=false

 public InstallResult addVirtualApp(AppInfoLite info) { // 174
        InstallOptions options = InstallOptions.makeOptions(info.notCopyApk, false, InstallOptions.UpdateStrategy.COMPARE_VERSION);

notify=true时,触发通知逻辑,允许外部获得安装回调,代码如下:

    private void notifyAppInstalled(PackageSetting setting, int userId) {
        final String pkg = setting.packageName;
        int N = mRemoteCallbackList.beginBroadcast();
        while (N-- > 0) {
            try {
                if (userId == -1) {
                    mRemoteCallbackList.getBroadcastItem(N).onPackageInstalled(pkg);
                    mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(0, pkg);

                } else {
                    mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(userId, pkg);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        sendInstalledBroadcast(pkg, new VUserHandle(userId));
        mRemoteCallbackList.finishBroadcast();
        VAccountManagerService.get().refreshAuthenticatorCache(null);
    }
    --->
     RemoteCallbackList<IPackageObserver> mRemoteCallbackList = new RemoteCallbackList<>()
   --->客户端注册:
      public void registerObserver(IPackageObserver observer) {
        try {
            getService().registerObserver(observer);
        } catch (RemoteException e) {
            VirtualRuntime.crash(e);
        }
    }     

mRemoteCallbackListVirtualCore.registerObserver注册。
sendInstalledBroadcast会广播ACTION_PACKAGE_ADDED消息,String ACTION_PACKAGE_ADDED = "virtual." + Intent.ACTION_PACKAGE_ADDED;,代码如下:

  public void sendBroadcastAsUser(Intent intent, VUserHandle user) { // 1150
        // intent包装一次设置成va自定义的action
        // eg: intent.setAction("virtual.android.intent.action.PACKAGE_ADDED")
        SpecialComponentList.protectIntent(intent);
        Context context = VirtualCore.get().getContext();
        if (user != null) {
            intent.putExtra("_VA_|_user_id_", user.getIdentifier());
        }
        context.sendBroadcast(intent);
    }

===> 12.客户端发起安装,接收安装结果:

客户端点击安装的代码流程如下:
添加App按钮点击事件为HomeActivity.onAddAppButtonClick
—>
ListAppActivity.gotoListApp(this); 请求的requestCodeVCommends.REQUEST_SELECT_APP
—>
ListAppActivity为显示系统已安装Apk界面,它由mViewPager构成:

mViewPager.setAdapter(new AppPagerAdapter(getSupportFragmentManager()));

—>
AppPagerAdapter一般是两个ListAppFragment组成, 第一页是设备上已安装的apk,和存储中下载好的可安装的apk包。
第一页dirs.add(null); 所以可以根据是否为null,来确认是否取得已安装apk还是下载的apk包。
new ListAppPresenterImpl(getActivity(), this, getSelectFrom()).start(); // 获得App列表(系统已安装的或系统内部存储已安装)。
内部通过Context.getPackageManager().getInstalledPackages(PackageManager.GET_PERMISSIONS)取得系统已安装的Apk列表
或通过findAndParseAPKs来遍历SCAN_PATH_LIST文件夹列表取得可安装的apk包。
—>
选中后的item操作位于ListAppFragment.onViewCreated中,

  mInstallButton.setOnClickListener( v -> { // 点击安装软件
            Integer[] selectedIndices = mAdapter.getSelectedIndices();
            ArrayList<AppInfoLite> dataList = new ArrayList<AppInfoLite>(selectedIndices.length);
            for (int index : selectedIndices) {
                AppInfo info = mAdapter.getItem(index);
                dataList.add(new AppInfoLite(info));
            }
            Intent data = new Intent();
            data.putParcelableArrayListExtra(VCommends.EXTRA_APP_INFO_LIST, dataList);
            getActivity().setResult(Activity.RESULT_OK, data);
            getActivity().finish();
        });

—>
getActivity().finish()后响应起始请求的requestCode(VCommends.REQUEST_SELECT_APP)

protected void onActivityResult(int requestCode, int resultCode, Intent data) { // 390
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == VCommends.REQUEST_SELECT_APP) {
            if (resultCode == RESULT_OK && data != null) {
                List<AppInfoLite> appList = data.getParcelableArrayListExtra(VCommends.EXTRA_APP_INFO_LIST);
                if (appList != null) {
                    for (AppInfoLite info : appList) {
                        mPresenter.addApp(info);
                    }
                }
            }
        }
        

—>
mPresenter.addApp(info);,其中mPresenter = new HomePresenterImpl(this);
–>
HomePresenterImpl.addApp内部使用了 jdeferred库异步安装,异步处理返回结果

  public void addApp(AppInfoLite info) {
        class AddResult {
            private PackageAppData appData;
            private int userId;
        }
        AddResult addResult = new AddResult();
        ProgressDialog dialog = ProgressDialog.show(mActivity, null, mActivity.getString(R.string.tip_add_apps));
        VUiKit.defer().when(() -> {
                 ...
                InstallResult res = mRepo.addVirtualApp(info);
                ...
            }
        }).then((res) -> {
            addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);
        }).fail((e) -> {
            dialog.dismiss();
        }).done(res -> {
            if (addResult.userId == 0) {
                PackageAppData data = addResult.appData;
                data.isLoading = true;
                mView.addAppToLauncher(data);
                handleLoadingApp(data);
            } else {
               // 多用户处理
               ...
            }
            dialog.dismiss();
        });
    }

–>
InstallResult res = mRepo.addVirtualApp(info);安装,mRepo = new AppRepository(mActivity);

–>
进入AppRepository类中:

 public InstallResult addVirtualApp(AppInfoLite info) {
        InstallOptions options = InstallOptions.makeOptions(info.notCopyApk, false, InstallOptions.UpdateStrategy.COMPARE_VERSION);
        return VirtualCore.get().installPackageSync(info.path, options);
    }
    
--->VirtualCore.get().installPackageSync的代码实现:
public InstallResult installPackageSync(String apkPath, InstallOptions options) {
        final ConditionVariable lock = new ConditionVariable();
        final InstallResult[] out = new InstallResult[1];
        installPackage(apkPath, options, new InstallCallback() {
            @Override
            public void onFinish(InstallResult result) {
                out[0] = result;
                lock.open();
            }
        });
        lock.block();
        return out[0];
    }
--->installPackage的代码实现:
public void installPackage(String apkPath, InstallOptions options, final InstallCallback callback) {
        ResultReceiver receiver = new ResultReceiver(null) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                resultData.setClassLoader(InstallResult.class.getClassLoader());
                if (callback != null) {
                    InstallResult res = resultData.getParcelable("result");
                    callback.onFinish(res);
                }
            }
        };
        try {
            getService().installPackage(apkPath, options, receiver);
        } catch (RemoteException e) {
            VirtualRuntime.crash(e);
        }
    }

getService().installPackage(apkPath, options, receiver);会调到VAMS中安装包的函数是installPackageImpl,也就是起始分析的地方。
onReceiveResult中接收安装结果。

4.5 VAMS中安装包完成后交互流程

回到 HomePresenterImpl.addApp函数, 再看一次:

 public void addApp(AppInfoLite info) {
        class AddResult {
            private PackageAppData appData;
            private int userId;
        }
        AddResult addResult = new AddResult();
        ProgressDialog dialog = ProgressDialog.show(mActivity, null, mActivity.getString(R.string.tip_add_apps));
        VUiKit.defer().when(() -> {
                 ...
                InstallResult res = mRepo.addVirtualApp(info);
                ...
            }
        }).then((res) -> {
            addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);
        }).fail((e) -> {
            dialog.dismiss();
        }).done(res -> {
            if (addResult.userId == 0) {// 默认用户
                PackageAppData data = addResult.appData;
                data.isLoading = true;
                mView.addAppToLauncher(data);
                handleLoadingApp(data);
            } else {
               // 多用户处理
               ...
            }
            dialog.dismiss();
        });
    }

在安装完成后,会返回InstallResult resres.isSuccess=ture表示成功,之后执行:

 addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);

PackageAppData类描述了它在VA中显示的名字和图标,如下定义:

public class PackageAppData extends AppData {
    public String packageName;
    public String name;
    public Drawable icon;

PackageAppDataStorage类用于缓存所有的PackageAppData,它的acquire函数定义如下:

    public PackageAppData acquire(String packageName) {
        PackageAppData data;
        synchronized (packageDataMap) {
            data = packageDataMap.get(packageName);// 先从本地缓存取
            if (data == null) {
                data = loadAppData(packageName);// 如果缓存没有,就从远程VAMS去取
            }
        }
        return data;
    }

—>loadAppData尝试从VPMS去取,如果成功,就加入本地缓存, 代码如下:

    private PackageAppData loadAppData(String packageName) { // 45
        InstalledAppInfo setting = VirtualCore.get().getInstalledAppInfo(packageName, 0);
        ....
        PackageAppData data = new PackageAppData(App.getApp(), setting);
        packageDataMap.put(packageName, data);// 如果成功,就加入本地缓存
         ...
    }

—>InstalledAppInfo settingVAMS交互取得,流程如下:

     --->VirtualCore类中的getInstalledAppInfo:
    public InstalledAppInfo getInstalledAppInfo(String pkg, int flags) {
            return getService().getInstalledAppInfo(pkg, flags);
            }
            
     --->调用到VAMS中:
      public InstalledAppInfo getInstalledAppInfo(String packageName, int flags) {
        synchronized (PackageCacheManager.class) {
            if (packageName != null) {
                PackageSetting setting = PackageCacheManager.getSetting(packageName);
                if (setting != null) {
                    return setting.getAppInfo();
                }
            }
            return null;
        }
    }

可以看到就是从前面提到的PackageCacheManager类中取。
—>将InstalledAppInfo setting转换成 PackageAppData dataPackageAppData的构造函数如下:

    public PackageAppData(Context context, InstalledAppInfo installedAppInfo) {
        this.packageName = installedAppInfo.packageName;
        this.isFirstOpen = !installedAppInfo.isLaunched(0);
        loadData(context, installedAppInfo.getApplicationInfo(installedAppInfo.getInstalledUsers()[0]));
    }
    --->loadData实现如下:
    private void loadData(Context context, ApplicationInfo appInfo) { // 28
        PackageManager pm = context.getPackageManager();
        name = appInfo.loadLabel(pm).toString();
        icon = appInfo.loadIcon(pm);
    }

—>loadData中第二个参数ApplicationInfo appInfoVPMS交互取得,流程如下:

    public ApplicationInfo getApplicationInfo(int userId) {
        return VPackageManager.get().getApplicationInfo(packageName, 0, userId);
    }
    
    --->VPackageManager类中的getApplicationInfo:
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
            return getService().getApplicationInfo(packageName, flags, userId);
     }
 --->远程VPMS中的getApplicationInfo:
     
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
          ...
            VPackage p = mPackages.get(packageName);
            if (p != null) {
                PackageSetting ps = (PackageSetting) p.mExtras;
                return PackageParserEx.generateApplicationInfo(p, flags, ps.readUserState(userId),
                        userId);
            }
        }
        return null;
    } 
    
     --->PackageParserEx.generateApplicationInfo:
    public static ApplicationInfo generateApplicationInfo(VPackage p, int flags,
                                                          PackageUserState state, int userId) {
      ...
        ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
        if ((flags & PackageManager.GET_META_DATA) != 0) {
            ai.metaData = p.mAppMetaData;
        }
        initApplicationAsUser(ai, userId);
        return ai;
    }

可以看出VPMS返回的是VPackage.applicationInfo

—>最后显示图标出来:

        }).done(res -> {
            if (addResult.userId == 0) {// 默认用户
                PackageAppData data = addResult.appData;
                data.isLoading = true;
                mView.addAppToLauncher(data); // HomeActivity
                handleLoadingApp(data);
       --->handleLoadingApp:
private void handleLoadingApp(AppData data) {
        VUiKit.defer().when(() -> {
           ....
        }).done((res) -> {
            if (data instanceof PackageAppData) {
                ((PackageAppData) data).isLoading = false;
                ((PackageAppData) data).isFirstOpen = true;
            } else if (data instanceof MultiplePackageAppData) {
                ((MultiplePackageAppData) data).isLoading = false;
                ((MultiplePackageAppData) data).isFirstOpen = true;
            }
            mView.refreshLauncherItem(data);
        });
    }

也就是通过HomeActivityaddAppToLauncherrefreshLauncherItem加载和显示安装APK的图标。

参考:
Android包管理机制

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值