一、安装的Activity
在Android,通过发送Intent可以启动应用的安装过程,如下所示:
- Uri uri = Uri.fromFile(new File(filename));
- Intent inent = new Intent(Intent.ACTION_VIEW);
- intent.SetDataAndType(uri, application/vnd.android.package-archive);
- startActivity(intent);
在Android的系统应用PackageInstaller中有一个PackageInstallActivity会响应这个Intent。在这个Activity中有两个重要的成员变量mPm和mInstaller,分别是ApplicationPackageManger和PackageInstaller的实例对象,这两个对象也是PackageManagerService和PackageInstallerService在应用中的代理对象。
PackageInstallerAcivity中创建这两个对象的代码如下:
- protected void onCreate(Bundler icicle) {
- super.onCreate(icicle);
- mPm = getPackageManager();
- mInstaller = mPm.getPackageInstaller();
- ......
- }
二、管理安装会话
PackageManagerInstallerService是Android5.0新加入的服务,主要用于管理安装会话(Installer session)。在Android5.0中,可以通过PackageManagerInstallerService来分配一个SessionId,这个系统唯一的ID代表一次安装过程,如果一个应用的安装分成几个阶段来完成,即使设备重启了,也可以通过这个ID来继续安装过程。
PackageManagerInstallerService中提供的接口createSession来创建一个Session:
- @Override
- public int createSession(SessionParams params, String installerPackageName, int userId) {
- try {
- return createSessionInternal(params, installerPackageName, userId);
- } catch (IOException e) {
- throw ExceptionUtils.wrap(e);
- }
- }
这个方法返回一个系统唯一值作为SessionID,如果希望再次使用这个Session,可以通过接口openSession方法来打开它,代码如下:
- @Override
- public IPackageInstallerSession openSession(int sessionId) {
- try {
- return openSessionInternal(sessionId);
- } catch (IOException e) {
- throw ExceptionUtils.wrap(e);
- }
- }
openSession返回一个IPackageInstallerSession对象,它是Binder服务PackageInstallerSession的IBinder对象。每个Install Session都会在SystemServer中有一个对应的PackageInstallerSession对象。在PackageInstallerService中mSessions数组保存了所有PackageInstallerSession对象,定义如下:
- private final SparseArray mSessions = new SparseArray<>();
当系统启动时,PackageManageService初始化时会创建PackageManagerInstallerService服务,在这个服务的初始化函数中,会读取/data/system目录下的install_sessions.xml文件,这个文件保存系统未完成的Install Session。然后PackagemanagerInstallerService会根据文件的内容创建PackageInstallerSession对象并插入mSessions中。
PackageInstallerSession中保存了应用安装相关的数据。例如,安装包路径,安装进度、中间数据保存的目录等。
三、应用安装过程
应用可以调用PackageManager的installPackage方法来开始安装过程,最终会调用到PackageManagerService的installPackage或者installPackageAsUser来执行安装过程,整个安装过程比较复杂。
整个安装过程可以分成两个阶段:
1.第一阶段把需要安装的应用复制到/data/app目录下
2.第二阶段是对apk文件扫描优化,装载到内存中。
3.1 复制文件
PackageManagerService的installPackage方法只是用当前用户安装应用,最后也会调用installPackageAsUser
- @Override
- 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方法:
- @Override
- public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
- int installFlags, String installerPackageName, VerificationParams verificationParams,
- String packageAbiOverride, int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
-
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");
-
- if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
- try {
- if (observer != null) {
- observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
- }
- } catch (RemoteException re) {
- }
- return;
- }
-
- if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
- installFlags |= PackageManager.INSTALL_FROM_ADB;
-
- } else {
-
-
-
- installFlags &= ~PackageManager.INSTALL_FROM_ADB;
- installFlags &= ~PackageManager.INSTALL_ALL_USERS;
- }
-
- UserHandle user;
- if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
- user = UserHandle.ALL;
- } else {
- user = new UserHandle(userId);
- }
-
- 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, observer, installFlags,
- installerPackageName, verificationParams, user, packageAbiOverride);
- mHandler.sendMessage(msg);
- }
installPackageAsUser先检查调用进程是否有安装应用的权限,再检查调用进程所属的用户是否有权限安装应用,最后检查指定的用户是否被限制安装应用。如果参数installFlags带有INSTALL_ALL_USERS,则该应用将给系统中所有用户安装,否则只给指定用户安装。
安装应用实践比较长,因此不可能在一个函数中完成。上面函数把数据保存在installParams然后发送了INIT_COPY消息。
下面我们再来看看消息处理:
- 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);
-
-
-
- if (!mBound) {
-
-
- if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
- params.serviceError();
- return;
- } else {
-
-
- mPendingInstalls.add(idx, params);
- }
- } else {
- mPendingInstalls.add(idx, params);
-
-
- if (idx == 0) {
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- }
- break;
- }
INIT_COPY消息的处理将绑定DefaultContainerService,因为这是一个异步的过程,要等待绑定的结果通过onServiceConnected返回,所以这里的安装参数放到了mPendingInstalls列表中。如果这个Service以前就绑定好了,现在就不需要再绑定,安装信息也会先放到mPendingInstalls。如果有多个安装请求同时到达,这里通过mPendingInstalls列表对他们进行排队。如果列表中只有一项,说明没有更多的安装请求,因此这种情况下回立即发出MCS_BOUND消息。而onServiceConnected方法同样是发出MCS_BOUND消息:
- class DefaultContainerConnection implements ServiceConnection {
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
- IMediaContainerService imcs =
- IMediaContainerService.Stub.asInterface(service);
- mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
- }
-
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
- }
- };
看下MCS_BOUND的消息处理
- case MCS_BOUND: {
- if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
- if (msg.obj != null) {
- mContainerService = (IMediaContainerService) msg.obj;
- }
- if (mContainerService == null) {
-
- Slog.e(TAG, "Cannot bind to media container service");
- for (HandlerParams params : mPendingInstalls) {
-
- params.serviceError();
- }
- mPendingInstalls.clear();
- } else if (mPendingInstalls.size() > 0) {
- HandlerParams params = mPendingInstalls.get(0);
- if (params != null) {
- if (params.startCopy()) {
-
-
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Checking for more work or unbind...");
-
- if (mPendingInstalls.size() > 0) {
- mPendingInstalls.remove(0);
- }
- if (mPendingInstalls.size() == 0) {
- if (mBound) {
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Posting delayed MCS_UNBIND");
- removeMessages(MCS_UNBIND);
- Message ubmsg = obtainMessage(MCS_UNBIND);
-
-
- sendMessageDelayed(ubmsg, 10000);
- }
- } else {
-
-
-
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Posting MCS_BOUND for next work");
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- }
- }
- } else {
-
- Slog.w(TAG, "Empty queue");
- }
- break;
- }
如果结束了我们看看MCS_UNBIND消息的处理
- case MCS_UNBIND: {
-
- if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");
-
- if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
- if (mBound) {
- if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");
-
- disconnectService();
- }
- } else if (mPendingInstalls.size() > 0) {
-
-
-
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
-
- break;
- }
MCS_UNBIND消息的处理,如果处理的时候发现mPendingInstalls又有数据了,还是发送MCS_BOUND消息继续安装,否则断开和DefaultContainerService的连接,安装结束。
下面我们看执行安装的函数startCopy:
- final boolean startCopy() {
- boolean res;
- try {
- if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
-
- if (++mRetries > MAX_RETRIES) {
- Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
- mHandler.sendEmptyMessage(MCS_GIVE_UP);
- handleServiceError();
- return false;
- } else {
- handleStartCopy();
- res = true;
- }
- } catch (RemoteException e) {
- if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
- mHandler.sendEmptyMessage(MCS_RECONNECT);
- res = false;
- }
- handleReturnCode();
- return res;
- }
handleStartCopy和copyApk代码就不分析了。
handleStartCopy函数先通过DefaultContainerService调用了getMinimallPackageInfo来确定安装位置是否有足够的空间,并在PackageInfoLite对象的recommendedIntallLocation记录错误原因。发现空间不够,会调用installer的freecache方法来释放一部分空间。
再接下来handleStartCopy有很长一段都在处理apk的校验,这个校验过程是通过发送Intent ACTION_PACKAGE_NEEDS_VERIFICATION给系统中所有接受该Intent的应用来完成。如果无需校验,直接调用InstallArgs对象的copyApk方法。
而copyApk方法同样是调用DefaultContainerService的copyPackage将应用的文件复制到/data/app下,如果还有native动态库,也会把包在apk文件中的动态库提取出来。
执行完copyApk后,应用安装到了data/app目录下了。
3.2 装载应用
接下来是第二阶段的工作,把应用的格式装换成oat格式,为应用创建数据目录。最后把应用信息装载进PackageManagerService的数据结构中。
接着上面startCopy方法最后会调用handleReturnCode方法,代码如下:
- @Override
- void handleReturnCode() {
-
-
-
- if (mArgs != null) {
- processPendingInstall(mArgs, mRet);
- }
- }
我们继续看下processPendingInstall函数。
- private void processPendingInstall(final InstallArgs args, final int currentStatus) {
-
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
-
- 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);
- }
- ..........
-
- if (!doRestore) {
-
- Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
- mHandler.sendMessage(msg);
- }
- }
- });
- }
processPendingInstall方法post了一个消息,这样安装过程以异步的方式继续执行。在post消息的处理中,首先调用installPackageLI来装载应用,然后很大的代码在执行备份,备份是通过BackupManagerService来完成的。备份完成后,通过发送POST_INSTALL消息来继续处理。而这个消息的处理主要就是在发送广播,应用安装完成后要通知系统中其他的应用开始处理,比如Launcher中需要增加应用的图标等。
我们来分析下installPackageLI方法:
- private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
- final int installFlags = args.installFlags;
- String installerPackageName = args.installerPackageName;
- File tmpPackageFile = new File(args.getCodePath());
- boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
- boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
- boolean replace = false;
- final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
-
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
-
- if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
-
- final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
- | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
- | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
- PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setDisplayMetrics(mMetrics);
-
- final PackageParser.Package pkg;
- try {
- pkg = pp.parsePackage(tmpPackageFile, parseFlags);
- } catch (PackageParserException e) {
- res.setError("Failed parse during installPackageLI", e);
- return;
- }
这里先调用parsePackage解析apk文件,这个之前分析过,我们就不再分析了。
继续分析processPendingInstall函数
- if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
- String oldName = mSettings.mRenamedPackages.get(pkgName);
- if (pkg.mOriginalPackages != null
- && pkg.mOriginalPackages.contains(oldName)
- && mPackages.containsKey(oldName)) {
-
-
-
-
- pkg.setPackageName(oldName);
- pkgName = pkg.packageName;
- replace = true;
- if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
- + oldName + " pkgName=" + pkgName);
- } else if (mPackages.containsKey(pkgName)) {
-
-
- replace = true;
- if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
- }
- }
继续分析
- if (systemApp && onSd) {
-
- res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- "Cannot install updates to system apps on sdcard");
- return;
- }
-
- if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
- res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
- return;
- }
继续分析
- if (replace) {
- replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
- installerPackageName, res);
- } else {
- installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
- args.user, installerPackageName, res);
- }
- synchronized (mPackages) {
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
- }
- }
下面我们分析下installNewPackageLI函数
- private void installNewPackageLI(PackageParser.Package pkg,
- int parseFlags, int scanFlags, UserHandle user,
- String installerPackageName, PackageInstalledInfo res) {
-
- String pkgName = pkg.packageName;
-
- if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
- boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
- synchronized(mPackages) {
- if (mSettings.mRenamedPackages.containsKey(pkgName)) {
-
-
-
-
- res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
- + " without first uninstalling package running as "
- + mSettings.mRenamedPackages.get(pkgName));
- return;
- }
- if (mPackages.containsKey(pkgName)) {
-
- res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
- + " without first uninstalling.");
- return;
- }
- }
-
- try {
- PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
- System.currentTimeMillis(), user);
-
- updateSettingsLI(newPackage, installerPackageName, null, null, res);
-
-
- if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-
-
-
-
- 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);
- }
- }
这里和上篇博客分析扫描apk文件类似,我们来看下这个函数scanPackageLI
- private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
- int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
- boolean success = false;
- try {
- final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
- currentTime, user);
- success = true;
- return res;
- } finally {
- if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
- removeDataDirsLI(pkg.packageName);
- }
- }
- }
scanPackageLI函数主要调用了scanPackageDirtyLI函数,这个函数前面分析过了就不分析了。
我们再来看下在processPendingInstall函数中调用完installPackageLI函数之后,发送了一个POST_INSTALL消息,我们来看下这个消息的处理
- case POST_INSTALL: {
- if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
- PostInstallData data = mRunningInstalls.get(msg.arg1);
- mRunningInstalls.delete(msg.arg1);
- boolean deleteOld = false;
-
- if (data != null) {
- InstallArgs args = data.args;
- PackageInstalledInfo res = data.res;
-
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- final String packageName = res.pkg.applicationInfo.packageName;
- res.removedInfo.sendBroadcast(false, true, false);
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, res.uid);
-
-
-
- if ((args.installFlags
- & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) {
- grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),
- args.installGrantPermissions);
- }
-
-
-
-
- int[] firstUsers;
- int[] updateUsers = new int[0];
- if (res.origUsers == null || res.origUsers.length == 0) {
- firstUsers = res.newUsers;
- } else {
- firstUsers = new int[0];
- for (int i=0; i
- int user = res.newUsers[i];
- boolean isNew = true;
- for (int j=0; j
- if (res.origUsers[j] == user) {
- isNew = false;
- break;
- }
- }
- if (isNew) {
- int[] newFirst = new int[firstUsers.length+1];
- System.arraycopy(firstUsers, 0, newFirst, 0,
- firstUsers.length);
- newFirst[firstUsers.length] = user;
- firstUsers = newFirst;
- } else {
- int[] newUpdate = new int[updateUsers.length+1];
- System.arraycopy(updateUsers, 0, newUpdate, 0,
- updateUsers.length);
- newUpdate[updateUsers.length] = user;
- updateUsers = newUpdate;
- }
- }
- }
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- packageName, extras, null, null, firstUsers);
- final boolean update = res.removedInfo.removedPackage != null;
- if (update) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- packageName, extras, null, null, updateUsers);
- if (update) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, null, null, updateUsers);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null, null, packageName, null, updateUsers);
-
-
- if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + res.pkg
- + " is ASEC-hosted -> AVAILABLE");
- }
- int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
- ArrayList pkgList = new ArrayList(1);
- pkgList.add(packageName);
- sendResourcesChangedBroadcast(true, true,
- pkgList,uidArray, null);
- }
- }
- if (res.removedInfo.args != null) {
-
- deleteOld = true;
- }
-
-
-
- if (firstUsers.length > 0) {
-
-
- if (packageIsBrowser(packageName, firstUsers[0])) {
- synchronized (mPackages) {
- for (int userId : firstUsers) {
- mSettings.setDefaultBrowserPackageNameLPw(null, userId);
- }
- }
- }
- }
-
- EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
- getUnknownSourcesSettings());
- }
-
- Runtime.getRuntime().gc();
-
- if (deleteOld) {
- synchronized (mInstallLock) {
- res.removedInfo.args.doPostDeleteLI(true);
- }
- }
- if (args.observer != null) {
- try {
- Bundle extras = extrasForInstallResult(res);
- args.observer.onPackageInstalled(res.name, res.returnCode,
- res.returnMsg, extras);
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
- } else {
- Slog.e(TAG, "Bogus post-install token " + msg.arg1);
- }
- } break;
这样安装应用的流程就讲完了。
流程的时序图
四 总结
我们主要分析一下scanPackageLI方法,还是仅仅分析,不帖代码,因为代码太长了,帖出来没法看了,这个方法不仅仅是完成apk包的扫描,还解析AndroidManifest.xml文件并提取出所有的intent-filter和permission信息,apk安装的主要功能都由它来完成的,当apk包扫描完成后,系统会调用updatePermissionsLPw方法更新系统所具有的权限。
scanPackageLI方法有两个,其第一个参数分别接受File和PackageParser.Package类型,第一个方法会从File中提取出package信息然后再调用第二个方法,下面分析第二个scanPackageLI方法,其完成的事情如下:
1. 如果包名是android,则会做一些特殊处理,这个包名为android的应用是系统内部应用的,其他应用的包名如果叫android则安装会有问题,大家可以试一下
2. 解析常见的use-feature、shared-userId、use-library标签并保存到成员变量中
3. 进行签名验证,对应的方法是verifySignaturesLP,验证失败则应用无法安装
4. 创建应用程序目录/data/data/包名,同时将apk中提取出dex文件并保存到/data/dalvik-cache,把apk当做zip解压就能得到dex文件
5. 解析AndroidManifest.xml文件,提取出所需信息,包括具有intent-filter的四大组件信息(Activity、Service、BroadcastReceiver、ContentProvider)和声明的系统权限等
到此为止,scanPackageLI方法结束了。而updatePermissionsLPw的作用是对系统中所有的权限进行更新,大家可以查看下/system/etc/permissons目录,下面定义了android系统中所有的权限,开发中最常用的权限定义在目录下的platform.xml里面,大家可以打开看看,可以看到常见的访问网络、读写外部存储等权限等都是在这里定义的。权限更新完毕以后,系统就会发送ACTION_PACKAGE_ADDED广播,告知所有应用有新应用安装了。另外,大家可以查看下data/system/目录,里面有两个文件packages.list和packages.xml,在packages.list里面放的是手机上安装的所有应用列表,而packages.xml中存放的是所有应用的设置应用,比如一个应用声明了哪些系统权限就定义在这里面。关于应用的卸载,我们可以想到是应用安装过程的逆过程,大致要做的是:停止应用、删除各种文件,更新系统设置、权限等,大家感兴趣自己看一下,完全是安装过程的逆过程,这里不介绍了。
6.关于 so 的拷贝我们还是照旧不细说 App 的安装流程了,主要还是和之前一样不论是替换还是新安装,都会调用 PackageManagerService 的 scanPackageLI() 函数,然后跑去 scanPackageDirtyLI 函数,而在这个函数中对于非系统的 APP 他调用了 derivePackageABI 这个函数,通过这个函数他将会觉得系统的abi是多少,并且也会进行我们最关心的 so 拷贝操作。