PackageManagerService启动流程和APK安装流程(Android 10)

3,303 阅读13分钟

PackageManagerService简称PKMS,Android系统的核心服务之一,是在SystemServer的run方法中的startBootstrapServices启动的,管理者着所有跟Package相关的工作,常见的比如**安装,卸载,信息查询等,**主要完成以下核心功能:

  1. 解析AndroidNanifest.xml清单文件,解析清单文件中的所有节点信息。
  2. 扫描.apk文件,安装系统应用,安装本地应用等。
  3. 管理本地应用,主要有, 安装,卸载,应用信息查询等。

PKMS调用方式

客户端可通过Context.getPackageManager()获得ApplicationPackageManager对象, 而mPM指向的是Proxy代理,当调用到mPM.方法后,将会调用到IPackageManager的Proxy代理方法,然后通过Binder机制中的mRemote与服务端PackageManagerService通信,并调用到PackageManagerService的方法。

Binder服务端:PackageManagerService继承于IPackageManager.Stub;

Binder客户端:ApplicationPackageManager(简称APM)的成员变量mPM继承于IPackageManager.Stub.Proxy; 本身APM是继承于PackageManager对象。

简单的调用如下:

/**
     * 得到应用层序的版本名称
     * 
     * @return
     */
    private String getVersionName() {
        PackageManager packageManager = getPackageManager();
        try {
            // 得到apk的功能清单文件:为了防止出错直接使用getPackageName()方法获得包名
            // packageManager.getPackageInfo("com.xxx.xxx", 0);
            PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
 
            //返回版本名称
            return packageInfo.versionName;
        } catch (NameNotFoundException e) {
            e.printStackTrace();
            return "";
        }
    }

PKMS启动过程分析

首先描述一下大致的启动流程:SystemServer.startBootstrapServices()函数中启动PKMS服务,再调用startOtherServices()函数中对dex优化,磁盘管理功能,让PKMS进入systemReady状态。

再来看一下PKMS的启动时序图和流程图,有助于我们了解大概的类调用和启动流程,下面在进行详细分析

PKMS启动时序图

PKMS启动流程图

具体步骤分析

第一步到第四步,都在startBootstrapServices()中,首先启动Intaller服务,也就是安装器,随后判断当前设备是否处于加密状态,如果只是解析核心应用,接着调用PKMS的静态方法main来创建pms对象。

  • 第一步:启动Installer服务(阻塞等待),以便有机会创建具有适当权限的关键目录,如/data/user,我们需要在初始化其他服务之前完成此任务
Installer installer = mSystemServiceManager.startService(Installer.class);
mActivityManagerService.setInstaller(installer);
  • 第二步:获取设备是否加密(手机设置密码),如果设备加密了,则只解析"core"应用
// Only run "core" apps if we're encrypting the device.
String cryptState = VoldProperties.decrypt().orElse("");
  • 第三步: 调用PKMS的main方法初始化PackageManagerService,其中调用PackageManagerService()构造函数创建了PKMS对象
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
//main方法
public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
  			// 检查Package编译相关系统属性
        PackageManagerServiceCompilerMapping.checkProperties();
				//执行pkms构造方法
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
  			//启动部分应用服务于多用户场景
        m.enableSystemUserPackages();
  			//往ServiceManager中注册"package"和"package_native"
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
    }
  • 第四步:如果设备没有加密,操作它。管理 A/B OTA dexopting.
// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
// Note: this isn't needed during decryption (we don't have /data anyways).
if (!mOnlyCore) {
  boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                                                         false);
  if (!disableOtaDexopt) {
    traceBeginAndSlog("StartOtaDexOptService");
    try {
      Watchdog.getInstance().pauseWatchingCurrentThread("moveab");
      OtaDexoptService.main(mSystemContext, mPackageManagerService);
    } catch (Throwable e) {
      reportWtf("starting OtaDexOptService", e);
    } finally {
      Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
      traceEnd();
    }
  }
}

第五,六,七步都在startOtherServices()方法中。

  • 第五步:如果设备没有加密,执行updatePackagesIfNeeded,完成Dex优化等
mPackageManagerService.updatePackagesIfNeeded();
//updatePackagesIfNeeded
@Override
    public void updatePackagesIfNeeded() {
        enforceSystemOrRoot("Only the system can request package update");

        // We need to re-extract after an OTA.
        boolean causeUpgrade = isDeviceUpgrading();

        // First boot or factory reset.
        // Note: we also handle devices that are upgrading to N right now as if it is their
        //       first boot, as they do not have profile data.
        boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;

        // We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
        boolean causePrunedCache = VMRuntime.didPruneDalvikCache();

        if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
            return;
        }

        List<PackageParser.Package> pkgs;
        synchronized (mPackages) {
            pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
        }

        final long startTime = System.nanoTime();
        final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
                    causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
                    false /* bootComplete */);

        final int elapsedTimeSeconds =
                (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);

        MetricsLogger.histogram(mContext, "opt_dialog_num_dexopted", stats[0]);
        MetricsLogger.histogram(mContext, "opt_dialog_num_skipped", stats[1]);
        MetricsLogger.histogram(mContext, "opt_dialog_num_failed", stats[2]);
        MetricsLogger.histogram(mContext, "opt_dialog_num_total", getOptimizablePackages().size());
        MetricsLogger.histogram(mContext, "opt_dialog_time_s", elapsedTimeSeconds);
    }
  • 第六步:执行performFstrimIfNeeded,完成磁盘维护
mPackageManagerService.performFstrimIfNeeded();
@Override
    public void performFstrimIfNeeded() {
        enforceSystemOrRoot("Only the system can request fstrim");

        // Before everything else, see whether we need to fstrim.
        try {
            IStorageManager sm = PackageHelper.getStorageManager();
            if (sm != null) {
                boolean doTrim = false;
                final long interval = Global.getLong(
                        mContext.getContentResolver(),
                        Global.FSTRIM_MANDATORY_INTERVAL,
                        DEFAULT_MANDATORY_FSTRIM_INTERVAL);
                if (interval > 0) {
                    final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
                    if (timeSinceLast > interval) {
                        doTrim = true;
                        Slog.w(TAG, "No disk maintenance in " + timeSinceLast
                                + "; running immediately");
                    }
                }
                if (doTrim) {
                    final boolean dexOptDialogShown;
                    synchronized (mPackages) {
                        dexOptDialogShown = mDexOptDialogShown;
                    }
                    if (!isFirstBoot() && dexOptDialogShown) {
                        try {
                            ActivityManager.getService().showBootMessage(
                                    mContext.getResources().getString(
                                            R.string.android_upgrading_fstrim), true);
                        } catch (RemoteException e) {
                        }
                    }
                    sm.runMaintenance();
                }
            } else {
                Slog.e(TAG, "storageManager service unavailable!");
            }
        } catch (RemoteException e) {
            // Can't happen; StorageManagerService is local
        }
    }

  • 第七步:调用systemReady,PKMS准备就绪
mPackageManagerService.systemReady();
PKMS构造方法

APK的扫描

PKMS的构造函数中调用了scanDirTracedLI方法来扫描某个目录的APK文件,Android10.0版本和其他低版本的扫描的路径是不一样的,PKMS主要扫描以下路径的APK信息,以下都属于系统app类别

/vendor/overlay
/product/overlay
/product_services/overlay
/odm/overlay
/oem/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/oem/priv-app
/product/priv-app
/product/app
/product_services/priv-app
/product_services/app
/product_services/priv-app
APK扫描流程图

在该流程中,可以看到AndroidManifest文件的解析后的所有信息存储在Package对象中。

APK扫描流程总结
  • 第一步:扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容
  • 第二步:解析清单文件到的信息由 Package 保存。从该类的成员变量可看出,和 Android四大组件相关的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此 activites 和 receivers等均声明为 ArrayList 。

APK的安装

APK的安装流程图(三大步骤)

APK安装时序图

具体步骤分析

点击一个apk后,会弹出安装界面,点击确定按钮后,会进入PackageInstallerActivitybindUi() 中的mAlert点击事件, 弹出的安装界面底部显示的是一个diaglog,主要由bindUi构成,上面有 ”取消“ 和 ”安装“ 两个按钮,点击安装后 调用startInstall()进行安装:

private void bindUi() {
    mAlert.setIcon(mAppSnippet.icon);
    mAlert.setTitle(mAppSnippet.label);
    mAlert.setView(R.layout.install_content_view);
    mAlert.setButton(DialogInterface.BUTTON_POSITIVE,
getString(R.string.install),
            (ignored, ignored2) -> {
                if (mOk.isEnabled()) {
                    if (mSessionId != -1) {
startInstall 做的事情
    mInstaller.setPermissionsResult(mSessionId, true);
    finish();
} else {
startInstall(); // 进行APK安装 下面开始分析 }
}
}, null);
    mAlert.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(R.string.cancel),
            (ignored, ignored2) -> {
                // Cancel and finish
                setResult(RESULT_CANCELED);
                if (mSessionId != -1) {
//如果mSessionId存在,执行setPermissionsResult()完成取消安装
                    mInstaller.setPermissionsResult(mSessionId, false);
                }
                finish();
            }, null);
    setupAlert();
    mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
    mOk.setEnabled(false);
}

startInstall方法组装了一个Intent,并跳转到 InstallInstalling 这个Activity,并关闭掉当前的PackageInstallerActivity。InstallInstalling主要用于向包管理器发送包的信息并处理包管理的回调:

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);
// 设置Intent中的class为 InstallInstalling,用来进行Activity跳转
// class InstallInstalling extends AlertActivity 下面会分析 InstallInstalling Activity
    newIntent.setClass(this, InstallInstalling.class);
    String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
    if (mOriginatingURI != null) {
        newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
    }
    if (mReferrerURI != null) {
        newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
    }
    if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
        newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
    }
    if (installerPackageName != null) {
        newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                installerPackageName);
    }
    if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
        newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
    }
    newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
    startActivity(newIntent);
    finish();
}

启动 InstallInstalling,进入onCreate, 重点是看onCreate函数中的六步:

protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ApplicationInfo appInfo = getIntent()
            .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
    mPackageURI = getIntent().getData();
    if ("package".equals(mPackageURI.getScheme())) {
        try {
            getPackageManager().installExistingPackage(appInfo.packageName);
            launchSuccess();
        } catch (PackageManager.NameNotFoundException e) {
            launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
        }
} else {
//根据mPackageURI创建一个对应的File
final File sourceFile = new File(mPackageURI.getPath()); PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo,
sourceFile);
        mAlert.setIcon(as.icon);
        mAlert.setTitle(as.label);
        mAlert.setView(R.layout.install_content_view);
        mAlert.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(R.string.cancel),
                (ignored, ignored2) -> {
                    if (mInstallingTask != null) {
                        mInstallingTask.cancel(true);
                    }
                    if (mSessionId > 0) {
 getPackageManager().getPackageInstaller().abandonSession(mSessionId);
                        mSessionId = 0;
}
                    setResult(RESULT_CANCELED);
                    finish();
                }, null);
        setupAlert();
        requireViewById(R.id.installing).setVisibility(View.VISIBLE);
// 第一步.如果savedInstanceState不为null,获取此前保存的mSessionId和 mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件id
        if (savedInstanceState != null) {
            mSessionId = savedInstanceState.getInt(SESSION_ID);
            mInstallId = savedInstanceState.getInt(INSTALL_ID);
            // Reregister for result; might instantly call back if result was
delivered while
            // activity was destroyed
try {
// 第二步.根据mInstallId向InstallEventReceiver注册一个观察者,
launchFinishBasedOnResult会接收到安装事件的回调, //无论安装成功或者失败都会关闭当前的Activity(InstallInstalling)。如果
savedInstanceState为null,代码的逻辑也是类似的 InstallEventReceiver.addObserver(this, mInstallId,
                        this::launchFinishBasedOnResult);
            } catch (EventResultPersister.OutOfIdsException e) {
                // Does not happen
}
} else {
// 第三步.创建SessionParams,它用来代表安装会话的参数,组装params
            PackageInstaller.SessionParams params = new
PackageInstaller.SessionParams(
                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
            params.setInstallAsInstantApp(false);
 params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
            params.setOriginatingUri(getIntent()
                    .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
 params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                    UID_UNKNOWN));
            params.setInstallerPackageName(getIntent().getStringExtra(
                    Intent.EXTRA_INSTALLER_PACKAGE_NAME));
            params.setInstallReason(PackageManager.INSTALL_REASON_USER);
// 第四步.根据mPackageUri对包(APK)进行轻量级的解析,并将解析的参数赋值给 SessionParams
            File file = new File(mPackageURI.getPath());
            try {
                PackageParser.PackageLite pkg =
PackageParser.parsePackageLite(file, 0);
                params.setAppPackageName(pkg.packageName);
                params.setInstallLocation(pkg.installLocation);
                params.setSize(
                			PackageHelper.calculateInstalledSize(pkg, false,
params.abiOverride));   
} catch (PackageParser.PackageParserException e) {
    Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming
    Log.e(LOG_TAG,
            "Cannot calculate installed size " + file + ". Try only
    params.setSize(file.length());
} catch (IOException e) {
    Log.e(LOG_TAG,
            "Cannot calculate installed size " + file + ". Try only
    params.setSize(file.length());
apk size.");
apk size.");
            }
try {
// 第五步.向InstallEventReceiver注册一个观察者返回一个新的mInstallId, //其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并
回调给EventResultPersister。
mInstallId = InstallEventReceiver
                        .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                this::launchFinishBasedOnResult);
            } catch (EventResultPersister.OutOfIdsException e) {
                launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
null);
}
try {
// 第六步.PackageInstaller的createSession方法内部会通过
IPackageInstaller与PackageInstallerService进行进程间通信, //最终调用的是PackageInstallerService的createSession方法来创建并返回
mSessionId
                mSessionId =
getPackageManager().getPackageInstaller().createSession(params);
            } catch (IOException e) {
                launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
null);
}
}
        mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
        mSessionCallback = new InstallSessionCallback();
    }
}

以上第六步是重点 PackageInstaller 的 createSession()内部会通过IPackageInstaller与 PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法 来创建并返回mSessionId。

InstallInstalling.onResume方法中,调用onPostExecute()方法,将APK的信息通过IO流的形式写入到PackageInstaller.Session中

protected void onResume() {
    super.onResume();
    // This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller(); // 获取sessionInfo
PackageInstaller.SessionInfo sessionInfo =
installer.getSessionInfo(mSessionId);
if (sessionInfo != null && !sessionInfo.isActive()) {
// 最终执行onPostExecute() 下面来分析
// 创建内部类InstallingAsyncTask的对象,调用execute(),最终进入
onPostExecute()
} }
    mInstallingTask = new InstallingAsyncTask();
    mInstallingTask.execute();
} else {
    // we will receive a broadcast when the install is finished
    mCancelButton.setEnabled(false);
    setFinishOnTouchOutside(false);
}    

Installinstalling.InstallingAsyncTask : 关注第一步和第二步

private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
    volatile boolean isDone;
// 第一步: doInBackground()会根据包(APK)的Uri,将APK的信息通过IO流的形式写入到 PackageInstaller.Session中
@Override
    protected PackageInstaller.Session doInBackground(Void... params) {
        PackageInstaller.Session session;
        try {
            session =
getPackageManager().getPackageInstaller().openSession(mSessionId);
        } catch (IOException e) {
            return null;
}
        session.setStagingProgress(0);
        try {
            File file = new File(mPackageURI.getPath());
            try (InputStream in = new FileInputStream(file)) {
                long sizeBytes = file.length();
                try (OutputStream out = session
                        .openWrite("PackageInstaller", 0, sizeBytes)) {
                    byte[] buffer = new byte[1024 * 1024];
                    while (true) {
                        int numRead = in.read(buffer);
                        if (numRead == -1) {
                            session.fsync(out);
                            break;
}
} }
                if (isCancelled()) {
                    session.close();
break; }
//将APK的信息通过IO流的形式写入到PackageInstaller.Session中 out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
                    float fraction = ((float) numRead / (float)
                    session.addProgress(fraction);
} }
    return session;
} catch (IOException | SecurityException e) {
    Log.e(LOG_TAG, "Could not write package", e);
    session.close();
    return null;
} finally {
sizeBytes);
} }
synchronized (this) {
    isDone = true;
    notifyAll();
}
// 第二步:最后在onPostExecute()中 调用PackageInstaller.Session的commit方法,进行 安装
@Override
    protected void onPostExecute(PackageInstaller.Session session) {
        if (session != null) {
            Intent broadcastIntent = new Intent(BROADCAST_ACTION);
            broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            broadcastIntent.setPackage(getPackageName());
            broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    InstallInstalling.this,
                    mInstallId,
                    broadcastIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
// commit 下面会分析
// 调用PackageInstaller.Session的commit方法,进行安装 session.commit(pendingIntent.getIntentSender()); mCancelButton.setEnabled(false); setFinishOnTouchOutside(false);
        } else {
 getPackageManager().getPackageInstaller().abandonSession(mSessionId);
            if (!isCancelled()) {
                launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
                }
            }
        }
  }

PackageInstaller的commit()

[PackageInstaller.java] commit
public void commit(@NonNull IntentSender statusReceiver) {
try {
// mSession的类型为IPackageInstallerSession,这说明要通过
IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit 方法,这样代码逻辑就到了Java框架层的。
// 调用IPackageInstallerSession的commit方法, 跨进程调用到 PackageInstallerSession.commit()
        mSession.commit(statusReceiver, false);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
    if (mIsPerfLockAcquired && mPerfBoostInstall != null) {
        mPerfBoostInstall.perfLockRelease();
        mIsPerfLockAcquired = false;
}
...
// 调用markAsCommitted()
if (!markAsCommitted(statusReceiver, forTransfer)) {
return; }
...
// 向Handler发送一个类型为MSG_COMMIT的消息 ,下面会分析
    mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}

MSG_COMMIT在handler中进行处理,进入handleCommit()

public boolean handleMessage(Message msg) {
    switch (msg.what) {
} }
case MSG_COMMIT:
    handleCommit();
break;
private void handleCommit() {
List<PackageInstallerSession> childSessions = getChildSessions();
    try {
        synchronized (mLock) {
//最终调用installStage(),进入PKMS
            commitNonStagedLocked(childSessions);
        }
    } catch (PackageManagerException e) {
        final String completeMsg = ExceptionUtils.getCompleteMessage(e);
        Slog.e(TAG, "Commit of session " + sessionId + " failed: " +
completeMsg);
        destroyInternal();
        dispatchSessionFinished(e.error, completeMsg, null);
    }
}

最终调用 mPm.installStage(),进入PKMS 【经过千辛万苦,终于要进入PKMS了】

private void commitNonStagedLocked(...)throws PackageManagerException {
    if (isMultiPackage()) {
...
mPm.installStage(activeChildSessions); // 【同学们注意】跨越进程 进入 PKMS.installStage了
    } else {
        mPm.installStage(committingSession);
} }

PKMS.installStage

[PackageManagerService.java]
void installStage(ActiveInstallSession activeInstallSession) {
    if (DEBUG_INSTANT) {
        if ((activeInstallSession.getSessionParams().installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " +
activeInstallSession.getPackageName());
        }
}
// 第一步.创建了类型为INIT_COPY的消息
final Message msg = mHandler.obtainMessage(INIT_COPY);
// 第二步.创建InstallParams,它对应于包的安装数据
final InstallParams params = new InstallParams(activeInstallSession);
 params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(pa
rams));
    msg.obj = params;
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
            System.identityHashCode(msg.obj));
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(msg.obj));
// 第三步.将InstallParams通过消息发送出去。
    mHandler.sendMessage(msg);
}
对INIT_COPY的消息的处理 [PackageManagerService.java]
void doHandleMessage(Message msg) {
    switch (msg.what) {
        case INIT_COPY: {
} }
    HandlerParams params = (HandlerParams) msg.obj;
    if (params != null) {
        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params)); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
// 执行APK拷贝动作,这里会执行到 final void startCopy() params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break; }
[PKMS.HandlerParams]
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); handleStartCopy();
handleReturnCode(); // 调用到下面 handleReturnCode
}
[PKMS.MultiPackageInstallParams]
void handleReturnCode() {
    if (mVerificationCompleted && mEnableRollbackCompleted) {
        .....
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = mArgs.copyApk(); // 下面会说到 copyApk
}
..... }
}            

APK 拷贝方法调用步骤如下:

PKMS
    copyApk()
    doCopyApk()
PackageManagerServiceUtils
    copyPacakge()
    copyFile()
安装的原理

安装其实就是把apk文件copy到对应的目录

  1. data/app/包名/,安装是吧apk文件复制到此目录,可以将文件取出并安装,和我们本身的apk是一样的,用该apk安装可能会遇到问题:用该命令 adb install -t <apk>来安装

  2. data/data/包名/,开辟存放应用程序的文件数据的文件夹,包括我们的so库,缓存文件,oat文件等。

注意:开机的时候,如果配置了odex优化,会生成上面的oat文件内容,后面手机重启后不会重复进行优化,除非系统升级或者恢复出厂设置等操作。

  1. 将apk中的dex文件安装到data/dalvik-cach目录下(dex文件时dalvik虚拟机的可执行文件)

PKMS之权限扫描

PackageManagerService中执行systemReady()以后,需要对/system/etc/permissions中各种xml进行扫描,进行相应的权限存储,供之后权限管理使用。

PackageManagerService执行systemReady()时,通过SystemConfig的readPermissionsFromXml()来扫描读取 /system/etc/permissions中的xml文件,包括platform.xml和系统支持的各种硬件模块的 feature主要工作:

PKMS权限扫描流程图

静默安装

// 如果想实现,静默安装,就需要设置好UID,只有设置这个UID后,才有安装的权限
// 但是这个UID必须要求有系统的[签名], 而这个系统的[签名]是属于各大手机厂商的机密,也 意味着非常的坑爹
// 如果是系统厂商要做这种静默安装, 那就是非常容易的事情, 因为系统厂商可以轻而易举的拿 到 系统的[签名]
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);
mSettings.addSharedUserLPw("android.uid.se", SE_UID,
        ApplicationInfo.FLAG_SYSTEM,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
        ApplicationInfo.FLAG_SYSTEM,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

requestPermissions源码流程解析

Google在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限危险权限(需要动态的申请并得到用户的授权才能使用)。

核心方法简介:

//检查权限
checkSelfPermission(@NonNull String permission) 
//申请权限
requestPermissions(@NonNull String[] permissions, int requestCode)
//处理结果回调
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults)
//是否需要显示UI界面提示用户为什么需要这个权限 
shouldShowRequestPermissionRationale(@NonNull String permission)
权限源码申请流程总结:
  • 第一步:MainActivity 调用 requestPermissions 进行动态权限申请;

  • 第二步:requestPermissions函数通过隐式意图,激活PackageInstaller的GrantPermissionsActivity界 面,让用户选择是否授权;

  • 第三步:经过PKMS把相关信息传递给PermissionManagerService处理;

  • 第四步:PermissionManagerService处理结束后回调给---->PKMS中的onPermissionGranted方法把处理结果返回;

  • 第五步:PKMS通知过程中权限变化,并调用writeRuntimePermissionsForUserLPr函数让PackageManager的settings记录下相关授权信息。

面试题

  1. 为什么手机启动那么耗时

    点击开机键,固定的地方启动开机动画,启动linux驱动,然后启动init进程(用户态第一个进程),init进程启动zogyte进程,zogyte启动SystemServer,SystemServer的main函数启动各种服务,PMS中的构造函数有五个阶段耗时,五个阶段后还会进行dex优化。

  2. startActivity MainActivity跳转到LoginActivity设置android:launcMode="singleTask",这个singleTask是什么时候被解析的? PKMS提前就进行加载了,存放在Package中了,Package里面有所有apk的配置信息,不需要再解析。

  3. 静态广播是什么时候注册的?

    手机开机的时候,PKMS构造函数, PKMS扫描进来Package,再进行注册

  4. 开机的时候,不会把apk重新安装一遍,那样太恐怖了,在ota(系统升级)的时候会进行重新安装一遍。

  5. SystemServer.run()方法简要介绍

    1. startBootstrapServices() 引导服务,AMS,PKMS,电源管理等等
    2. startCoreServices() 核心服务
    3. startOtherServices() 其他服务
  6. 安装新的apk过程,何时进行配置文件的获取(扫描),PackageInstallerActivity的onCreate方法中processPackageUri,该方法只是进行权限等内容的扫描,不会全部扫描,执行安装方法之前,真正进行扫描的方法是在PKMS.installPackageLI方法

    //PackageInstallerActivity.java  界面弹出框
    protected void onCreate(Bundle icicle) {
        getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
        super.onCreate(null);
        // 初始化安装需要用到的对象
        mPm = getPackageManager();
        mIpm = AppGlobals.getPackageManager();
        mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
        mInstaller = mPm.getPackageInstaller();
        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
    
        // 根据Uri的Scheme做不同的处理,这里面进行扫描。
        boolean wasSetUp = processPackageUri(packageUri);
        if (!wasSetUp) {
            return;
        }
        // 显示安装界面
        bindUi();
        // 检查是否允许安装包,如果允许则启动安装。如果不允许显示适当的对话框
        checkIfAllowedAndInitiateInstall();
    }
    
    

    主要做了对象的初始化,解析 Uri 的 Scheme,初始化界面,安装包检查等等工作,接着查看一下 processPackageUri 方法,这里只是获取一些权限,名字,icon等等,没有进行全部解析AndroidManifest.xml文件,各个厂商可以自己定制。

    真正进行全部扫描的方法是在PKMS.installPackageLI。

参考文章:

apk dex vdex odex art 区别

juejin.cn/post/684490…