PMS源码探究相关记录 - Xiasm/Java-Android-Learn GitHub Wiki

简介

    包管理机制是Android中一个重要的知识点,分析Android的包管理机制可以让我们更加熟悉framework层的工作方式。

分析的入口

包管理机制最重要的就是apk包的安装,所以我们从安装apk开始分析。Android APK的安装场景有很多种,如:

  • adb install
  • 用户下载的apk通过系统安装器安装
  • 通过应用商店安装

我们就从开发最常用的用户下载apk调用系统安装器安装开始分析。在Android7.0之前,我们通过下面代码启动apk的安装程序,可见这是一个隐式调用:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
context.startActivity(intent);

Android7.0之后,再这么做会报FileUriExposedException异常,这是因为StrictMode API 政策禁止应用程序将file:// Uri暴露给另一个应用程序,而我们的系统安装器就是一个内置在系统里的应用程序。为解决这个问题,google提供了FileProvider,这里我们不再陈述,因为它并不影响我们调用系统安装器的核心代码。

在我们的应用程序调用安装apk的代码里,会有这么两句:

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");

可见我们要调用的activity在manifest文件里一定声明了一个过滤器如下:

-<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="file"/>
    <data android:scheme="content"/>
    <data android:mimeType="application/vnd.android.package-archive"/>
</intent-filter>

我们这里是基于Android 7.1的源码进行分析,在源码解压后的文件夹里,会有一个packages文件夹,点击进入,打开apps文件夹,可见这里都是系统内置的应用程序。其中有一个文件夹PackageInstaller,就是我们的系统安装器应用程序,打开如下

点击打开AndroidManifest.xml文件,然后搜索“application/vnd.android.package-archive”,会找到一下activity配置:


PackageInstallerActivity就是PackageInstaller的入口Activity,下面我们看一下PackageInstallerActivity onCreate处的代码:
目录:E:\Android_7_1_SourceCode\android-7.1.0_r1\packages\apps\PackageInstaller\src\com\android\packageinstaller

@Override
protected void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    mPm = getPackageManager();
    mInstaller = mPm.getPackageInstaller();
    mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);

    final Intent intent = getIntent();
    mOriginatingUid = getOriginatingUid(intent);

    final Uri packageUri;
    //标注1
    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);
        if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
            Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
            finish();
            return;
        }

        mSessionId = sessionId;
        packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
        mOriginatingURI = null;
        mReferrerURI = null;
    } else {
        mSessionId = -1;
        packageUri = intent.getData();
        mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
        mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
    }

    // if there's nothing to do, quietly slip into the ether
    if (packageUri == null) {
        Log.w(TAG, "Unspecified source");
        setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
        finish();
        return;
    }

    //...

    //set view
    setContentView(R.layout.install_start);
    mInstallConfirm = findViewById(R.id.install_confirm_panel);
    mInstallConfirm.setVisibility(View.INVISIBLE);
    mOk = (Button)findViewById(R.id.ok_button);
    mCancel = (Button)findViewById(R.id.cancel_button);
    mOk.setOnClickListener(this);
    mCancel.setOnClickListener(this);

    // Block the install attempt on the Unknown Sources setting if necessary.
    //标注2
    final boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
    if (!requestFromUnknownSource) {
        processPackageUri(packageUri);
        return;
    }

    // If the admin prohibits it, or we're running in a managed profile, just show error
    // and exit. Otherwise show an option to take the user to Settings to change the setting.
    final boolean isManagedProfile = mUserManager.isManagedProfile();
    if (isUnknownSourcesDisallowed()) {
        if ((mUserManager.getUserRestrictionSource(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                Process.myUserHandle()) & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
            showDialogInner(DLG_UNKNOWN_SOURCES);
        } else {
            startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
            clearCachedApkIfNeededAndFinish();
        }
    } else if (!isUnknownSourcesEnabled() && isManagedProfile) {
        showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
    } else if (!isUnknownSourcesEnabled()) {
        // Ask user to enable setting first

        showDialogInner(DLG_UNKNOWN_SOURCES);
    } else {
        processPackageUri(packageUri);
    }
}

在onCreate的开头首先会初始化安装所需要的各种对象,如PackageManager、UserManager、PackageInstaller等。 在标注1处有个判断,intent的action如果是ACTION_CONFIRM_PERMISSIONS,显然我们不是,进入else里面,则packageUri就是我们通过setDataAndType传入的uri。
接着看标注2,会通过isInstallRequestFromUnknownSource(intent)方法检测是否是未知来源,如果不是,执行processPackageUri(packageUri)方法。如果是未知来源,会弹框提示,这里我们不在分析,因为用户同意安装未知来源的apk后,还是会走入processPackageUri方法。这里我把processPackageUri方法贴出来:

private void processPackageUri(final Uri packageUri) {
    mPackageURI = packageUri;

    final String scheme = packageUri.getScheme();
    final PackageUtil.AppSnippet as;

    switch (scheme) {
        case SCHEME_PACKAGE: {
            try {
                mPkgInfo = mPm.getPackageInfo(packageUri.getSchemeSpecificPart(),
                        PackageManager.GET_PERMISSIONS
                                | PackageManager.GET_UNINSTALLED_PACKAGES);
            } catch (NameNotFoundException e) {
            }
            if (mPkgInfo == null) {
                Log.w(TAG, "Requested package " + packageUri.getScheme()
                        + " not available. Discontinuing installation");
                showDialogInner(DLG_PACKAGE_ERROR);
                setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
                return;
            }
            as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),
                    mPm.getApplicationIcon(mPkgInfo.applicationInfo));
        } break;
        //标注1
        case SCHEME_FILE: {
            File sourceFile = new File(packageUri.getPath());
            PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);

            // Check for parse errors
            if (parsed == null) {
                Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
                showDialogInner(DLG_PACKAGE_ERROR);
                setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
                return;
            }
            //标注2
            mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
                    PackageManager.GET_PERMISSIONS, 0, 0, null,
                    new PackageUserState());
            as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
        } break;

        case SCHEME_CONTENT: {
            mStagingAsynTask = new StagingAsyncTask();
            mStagingAsynTask.execute(packageUri);
            return;
        }

        default: {
            Log.w(TAG, "Unsupported scheme " + scheme);
            setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
            clearCachedApkIfNeededAndFinish();
            return;
        }
    }

    PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
    //标注3
    initiateInstall();
}

直接看标注1处,因为我们的uri无论有没有通过FileProvider进行处理,最后还是file的协议。然后通过PackageUtil.getPackageInfo(sourceFile)解析这个file(这个file实际上就是一个apk文件)得到Package,标注2处会根据uid、用户状态信息和PackageManager的配置等变量对包信息Package做进一步处理得到PackageInfo。
mPkgInfo拿到之后看标注3,会执行initiateInstall()方法,代码如下:

private void initiateInstall() {
    //标注1
    String pkgName = mPkgInfo.packageName;
    // Check if there is already a package on the device with this name
    // but it has been renamed to something else.
    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 {
        // This is a little convoluted because we want to get all uninstalled
        // apps, but this may include apps with just data, and if it is just
        // data we still want to count it as "installed".

        //标注2
        mAppInfo = mPm.getApplicationInfo(pkgName,
                PackageManager.GET_UNINSTALLED_PACKAGES);
        if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
            mAppInfo = null;
        }
    } catch (NameNotFoundException e) {
        mAppInfo = null;
    }

    startInstallConfirm();
}

标注1处通过mPkgInfo拿到pkgName,标注2处通过pkgName拿到应用程序的信息mAppInfo,然后调用startInstallConfirm()方法确认安装。startInstallConfirm()方法如下:

private void startInstallConfirm() {
    TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
    tabHost.setup();
    tabHost.setVisibility(View.VISIBLE);
    ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
    TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
    // If the app supports runtime permissions the new permissions will
    // be requested at runtime, hence we do not show them at install.
    boolean supportsRuntimePermissions = mPkgInfo.applicationInfo.targetSdkVersion
            >= Build.VERSION_CODES.M;
    boolean permVisible = false;
    mScrollView = null;
    mOkCanInstall = false;
    int msg = 0;

    //标注1
    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);
            if (newPermissionsFound) {
                permVisible = true;
                mScrollView.addView(perms.getPermissionsView(
                        AppSecurityPermissions.WHICH_NEW));
            }
        }
        if (!supportsRuntimePermissions && !newPermissionsFound) {
            LayoutInflater inflater = (LayoutInflater)getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            TextView label = (TextView)inflater.inflate(R.layout.label, null);
            label.setText(R.string.no_new_perms);
            mScrollView.addView(label);
        }
        adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
                getText(R.string.newPerms)), mScrollView);
    } else  {
        findViewById(R.id.tabscontainer).setVisibility(View.GONE);
        findViewById(R.id.spacer).setVisibility(View.VISIBLE);
    }
    if (!supportsRuntimePermissions && N > 0) {
        permVisible = true;
        LayoutInflater inflater = (LayoutInflater)getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        View root = inflater.inflate(R.layout.permissions_list, null);
        if (mScrollView == null) {
            mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview);
        }
        ((ViewGroup)root.findViewById(R.id.permission_list)).addView(
                    perms.getPermissionsView(AppSecurityPermissions.WHICH_ALL));
        adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator(
                getText(R.string.allPerms)), root);
    }

  //...
    //标注2
    mInstallConfirm.setVisibility(View.VISIBLE);
        mOk.setEnabled(true);
        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;
                }
            });
        }
}

startInstallConfirm()方法会首先初始化确认安装界面,就是我们平常的安装apk界面,注意不同厂商定制的系统对这一块可能会有更改。标注1处会通过上面拿到的mPkgInfo去得到apk需要的权限信息,并通过CaffeinatedScrollView这个view展示出来,到这一步PackageInstaller安装apk的初始化工作就完成了。

开始安装

看上面代码的标注2,mOk.setEnabled(true),这个mOk就是确认安装按钮。开始安装apk需要用户点击确认安装按钮触发,那么我们就直接来看onClick(View v)方法的代码:

public void onClick(View v) {
    if (v == mOk) {
        if (mOkCanInstall || mScrollView == null) {
            if (mSessionId != -1) {
                mInstaller.setPermissionsResult(mSessionId, true);
                clearCachedApkIfNeededAndFinish();
            } else {
                //标注1
                startInstall();
            }
        } else {
            mScrollView.pageScroll(View.FOCUS_DOWN);
        }
    } else if (v == mCancel) {
        // Cancel and finish
        setResult(RESULT_CANCELED);
        if (mSessionId != -1) {
            mInstaller.setPermissionsResult(mSessionId, false);
        }
        clearCachedApkIfNeededAndFinish();
    }
}

由上面onCreate处代码分析可知,此时mSessionId为-1,则走入标注1处startInstall()方法。

private void startInstall() {
    // Start subactivity to actually install the application
    Intent newIntent = new Intent();
    //标注1
    newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
            mPkgInfo.applicationInfo);
    newIntent.setData(mPackageURI);
    newIntent.setClass(this, InstallAppProgress.class);
    String installerPackageName = getIntent().getStringExtra(
            Intent.EXTRA_INSTALLER_PACKAGE_NAME);
    if (mOriginatingURI != null) {
        newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
    }
    if (mReferrerURI != null) {
        newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
    }
    if (mOriginatingUid != VerificationParams.NO_UID) {
        newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
    }
    if (installerPackageName != null) {
        newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                installerPackageName);
    }
    if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
        newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    }
    if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
    startActivity(newIntent);
    finish();
}

看标注1出知,安装apk跳到了InstallAppProgress这个activity,并把获取到的mPkgInfo的applicationInfo传入extras。可以看到这时也把我们通过隐式Intent设置的data重新传给了InstallAppProgress这个activity,接下来我们看下InstallAppProgress这个类
文件位置:E:\Android_7_1_SourceCode\android-7.1.0_r1\packages\apps\PackageInstaller\src\com\android\packageinstaller
看此类介绍可知,这个类主要作用是安装apk并显示进度等等,我们直接看onCreate()处的代码:

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    Intent intent = getIntent();
    mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
    mPackageURI = intent.getData();

    final String scheme = mPackageURI.getScheme();
    if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
        throw new IllegalArgumentException("unexpected scheme " + scheme);
    }

    mInstallThread = new HandlerThread("InstallThread");
    mInstallThread.start();
    mInstallHandler = new Handler(mInstallThread.getLooper());

    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(BROADCAST_ACTION);
    registerReceiver(
            mBroadcastReceiver, intentFilter, BROADCAST_SENDER_PERMISSION, null /*scheduler*/);

    initView();
}

看到这里注册了一个广播,新建一个handler用来处理安装过程中的各种状态,然后又走入initView()方法。

void initView() {
    setContentView(R.layout.op_progress);

    final PackageUtil.AppSnippet as;
    final PackageManager pm = getPackageManager();
    final int installFlags = getInstallFlags(mAppInfo.packageName);

    if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
        Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
    }
    if ("package".equals(mPackageURI.getScheme())) {
        as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo),
                pm.getApplicationIcon(mAppInfo));
    } else {
        final File sourceFile = new File(mPackageURI.getPath());
        as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile);
    }
    mLabel = as.label;
    PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
    mStatusTextView = (TextView)findViewById(R.id.center_text);
    mExplanationTextView = (TextView) findViewById(R.id.explanation);
    mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
    mProgressBar.setIndeterminate(true);
    // Hide button till progress is being displayed
    mOkPanel = findViewById(R.id.buttons_panel);
    mDoneButton = (Button)findViewById(R.id.done_button);
    mLaunchButton = (Button)findViewById(R.id.launch_button);
    mOkPanel.setVisibility(View.INVISIBLE);

    if ("package".equals(mPackageURI.getScheme())) {
        try {
            pm.installExistingPackage(mAppInfo.packageName);
            onPackageInstalled(PackageInstaller.STATUS_SUCCESS);
        } catch (PackageManager.NameNotFoundException e) {
            onPackageInstalled(PackageInstaller.STATUS_FAILURE_INVALID);
        }
    } else {
      //标注1
        final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        params.referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
        params.originatingUri = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
        params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                UID_UNKNOWN);
        //标注2
        File file = new File(mPackageURI.getPath());
        try {
            params.setInstallLocation(PackageParser.parsePackageLite(file, 0).installLocation);
        } catch (PackageParser.PackageParserException e) {
            Log.e(TAG, "Cannot parse package " + file + ". Assuming defaults.");
        }

        mInstallHandler.post(new Runnable() {
            @Override
            public void run() {
                doPackageStage(pm, params);
            }
        });
    }
}

因为我们通过隐式意图传入的是file协议,所以直接看标注1处,会创建SessionParams,它是安装程序会话的参数。注意到PackageInstaller这个类,这个类是整个安装的核心类,它在android.content.pm包下面,这个类主要提供在设备上安装,升级和删除应用程序等的功能。标注2处对安装包进行位置等解析,然后执行doPackageStage()方法并把解析的params传过去。接下来我们看下doPackageStage(pm, params)方法:

private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
    final PackageInstaller packageInstaller = pm.getPackageInstaller();
    PackageInstaller.Session session = null;
    try {
        //标注1
        final String packageLocation = mPackageURI.getPath();
        final File file = new File(packageLocation);
        final int sessionId = packageInstaller.createSession(params);
        final byte[] buffer = new byte[65536];

        session = packageInstaller.openSession(sessionId);

        final InputStream in = new FileInputStream(file);
        final long sizeBytes = file.length();
        final OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes);
        try {
            int c;
            while ((c = in.read(buffer)) != -1) {
                out.write(buffer, 0, c);
                if (sizeBytes > 0) {
                    final float fraction = ((float) c / (float) sizeBytes);
                    session.addProgress(fraction);
                }
            }
            session.fsync(out);
        } finally {
            IoUtils.closeQuietly(in);
            IoUtils.closeQuietly(out);
        }

        // Create a PendingIntent and use it to generate the IntentSender
        Intent broadcastIntent = new Intent(BROADCAST_ACTION);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                InstallAppProgress.this /*context*/,
                sessionId,
                broadcastIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        //标注2
        session.commit(pendingIntent.getIntentSender());
    } catch (IOException e) {
        onPackageInstalled(PackageInstaller.STATUS_FAILURE);
    } finally {
        IoUtils.closeQuietly(session);
    }
}

标注1处可看出,拿到文件位置之后,会通过流去读文件,session.fsync(out)会将流数据刷到磁盘.然后看标注2,session会话会进行提交,并传入一个IntentSender,我们来看下commit方法的实现:
文件目录:android.content.pm.PackageInstaller

public void commit(@NonNull IntentSender statusReceiver) {
    try {
        mSession.commit(statusReceiver);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

mSeesion是Session类持有的一个对象,如下:

public static class Session implements Closeable {
       private IPackageInstallerSession mSession;

       //...
}

这说明要通过IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit方法,这样代码逻辑就到了Java框架层的。
文件位置:E:\Android_7_1_SourceCode\android-7.1.0_r1\frameworks\base\services\core\java\com\android\server\pm

@Override
public void commit(IntentSender statusReceiver) {
    Preconditions.checkNotNull(statusReceiver);

    final boolean wasSealed;
    synchronized (mLock) {
        wasSealed = mSealed;
        if (!mSealed) {
            // Verify that all writers are hands-off
            for (FileBridge bridge : mBridges) {
                if (!bridge.isClosed()) {
                    throw new SecurityException("Files still open");
                }
            }
            mSealed = true;
        }

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

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

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

    final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
            statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
    //标注1
    mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
}

commit方法中会将包的信息封装为PackageInstallObserverAdapter ,它在PMS中被定义。在标注1处会向Handler发送一个类型为MSG_COMMIT的消息,其中adapter.getBinder()会得到IPackageInstallObserver2.Stub类型的观察者,从类型就知道这个观察者是可以跨进程进行回调的。处理该消息的代码如下所示。

private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        synchronized (mLock) {
            if (msg.obj != null) {
                mRemoteObserver = (IPackageInstallObserver2) msg.obj;
            }

            try {
                commitLocked();
            } catch (PackageManagerException e) {
                final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
                destroyInternal();
                dispatchSessionFinished(e.error, completeMsg, null);
            }

            return true;
        }
    }
};

我们直接看commitLocked()方法:

private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
          throws PackageManagerException {
     ...
      mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
              installerPackageName, installerUid, user, mCertificates);
  }

commitLocked方法比较长,这里截取最主要的信息,会调用PMS的installStage方法,这样代码逻辑就进入了PMS中。

参考

Android包管理机制

⚠️ **GitHub.com Fallback** ⚠️