赞
踩
本文源代码基于 Android 7.0。
在 Android 系统下,我们一般会使用 "adb install -r" 命令来安装应用,此时应用会被安装到 /data/app/ 下。这篇文章,我们就简要分析 PackageManagerService 安装 APK 的中间处理过程。
目录:
1. 安装流程图
2. adb 方式安装 APK
在进入 PackageManager 之前,我们先看下有关 adb 安装应用的内容。在 Android 中,adbd 以后台进程运行 (init 进程解析 init.rc 生成的进程,Installer 中真正干活的进程)。
当我们输入 "adb install" 命令时,/system/core/adb/ 目录下 commandline.cpp 文件会被执行,其中 adb_commandline() 函数会接受该条指令,并进行处理,这里只看 install 命令的执行:
- else if (!strcmp(argv[0], "install")) {
- if (argc < 2) return usage();
- if (_use_legacy_install()) {
- // 安装应用(legacy模式)
- return install_app_legacy(transport_type, serial, argc, argv);
- }
- // 安装应用
- return install_app(transport_type, serial, argc, argv);
- }
-
- ......
- }
这里以 legacy 模式为例:
- static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
- static const char *const DATA_DEST = "/data/local/tmp/%s";// 安装到 data 目录下时,会将 apk 先拷贝一份到该目录下
- static const char *const SD_DEST = "/sdcard/tmp/%s";//安装到 SD 卡上时,会将 apk 先拷贝一份到 /sdcard/tmp/ 目录下; 一般带参数 -s
- const char* where = DATA_DEST;
- int i;
- struct stat sb;
-
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-s")) {
- where = SD_DEST;
- }
- }
-
- // Find last APK argument.
- // All other arguments passed through verbatim.
- int last_apk = -1;
- for (i = argc - 1; i >= 0; i--) {
- const char* file = argv[i];
- const char* dot = strrchr(file, '.');
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return EXIT_FAILURE;
- }
-
- last_apk = i;
- break;
- }
- }
-
- if (last_apk == -1) {
- fprintf(stderr, "Missing APK file\n");
- return EXIT_FAILURE;
- }
-
- int result = -1;
- std::vector<const char*> apk_file = {argv[last_apk]};
- std::string apk_dest = android::base::StringPrintf(
- where, adb_basename(argv[last_apk]).c_str());
- // 我们即将安装的 apk 文件也许会在客户机上, 这里会先将该apk文件推送到系统的 /data/local/tmp/目录下
- if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
- argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
- // 执行 pm 脚本, 进行安装
- result = pm_command(transport, serial, argc, argv);
-
- cleanup_apk:
- // 安装过程结束后,会清掉事先拷贝的那一份apk
- delete_file(transport, serial, apk_dest);
- return result;
- }
由于我们使用 adb 安装的 APK 有可能会在客户机上,所以这里会先将 APK 文件拷贝一份到系统的 /data/local/tmp/ 目录下。
然后流程会去执行 pm 脚本进行安装操作。手机的端的 adbd 程序接收到客户机发送的 shell pm 命令后,会开启一个 shell 去执行 pm 脚本。pm 脚本的内容如下:
- # Script to start "pm" on the device, which has a very rudimentary
- # shell.
- #
- base=/system
- export CLASSPATH=$base/framework/pm.jar
- exec app_process $base/bin com.android.commands.pm.Pm "$@"
该脚本在系统编译时会被打包成 /system/bin/pm 可执行程序,执行 pm 可执行程序其实就是执行这段脚本。
我们知道,app_process 在系统启动过程中会去启动 Zygote 系统进程。同时,它也可以被用来启动一些其他的普通进程,比如此时的 pm。我们直接看启动 pm 时调用的 main() 函数,com.android.commands.pm.Pm::main():
- public static void main(String[] args) {
- int exitCode = 1;
- try {
- exitCode = new Pm().run(args);
- } catch (Exception e) {
- Log.e(TAG, "Error", e);
- System.err.println("Error: " + e);
- if (e instanceof RemoteException) {
- System.err.println(PM_NOT_RUNNING_ERR);
- }
- }
- System.exit(exitCode);
- }
创建 Pm 实例并调用它的 run() 方法:
- public int run(String[] args) throws RemoteException {
- boolean validCommand = false;
- if (args.length < 1) {
- return showUsage();
- }
- mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
- mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
- // IPackageManager实例,通过它可以调用到PackageManagerServcie中,就是binder的客户端
- mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
-
- // IPackageManager实例为空,即返回
- if (mPm == null) {
- System.err.println(PM_NOT_RUNNING_ERR);
- return 1;
- }
- // IPackageInstaller实例,它会管理android中的应用安装状态
- mInstaller = mPm.getPackageInstaller();
-
- mArgs = args;
- String op = args[0];
- mNextArg = 1;
-
- if ("list".equals(op)) {
- return runList();
- }
-
- if ("path".equals(op)) {
- return runPath();
- }
-
- if ("dump".equals(op)) {
- return runDump();
- }
-
- if ("install".equals(op)) {
- // 此处分析的是install命令,走这条分支
- return runInstall();
- }
- ......
- }
因为我们传入的是 install 命令,所以执行 runInstall() 函数;至此,安装过程就即将进入 PackageManagerService 了。同时我们也可以调用 PackageManager::installPackage() 函数安装应用,这种方式的安装与 adb install 的安装流程在进入PackageManagerService 之后,都是一样的。
3. PackageManager 安装 APK
PackageManager 的功能由 ApplicationPackageManager 实现,ApplicationPackageManager 内部持有一个指向PackageManagerService 的 mPM 对象来传递函数调用。当我们调用 PackageManager::installPackage() 时,实际调用ApplicationPackageManager 中的实现函数:
- @Override
- public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
- String installerPackageName) {
- installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
- installerPackageName, mContext.getUserId());
- }
-
- @Override
- public void installPackage(Uri packageURI, PackageInstallObserver observer,
- int flags, String installerPackageName) {
- installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
- }
-
- private void installCommon(Uri packageURI,
- PackageInstallObserver observer, int flags, String installerPackageName,
- int userId) {
- if (!"file".equals(packageURI.getScheme())) {
- throw new UnsupportedOperationException("Only file:// URIs are supported");
- }
-
- final String originPath = packageURI.getPath();
- try {
- mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
- userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
方法中传入了一个 PackageInstallObserver 对象,它是用户用来监听 APK 安装的最后结果的。PackageInstallObserver 的定义如下:
- public class PackageInstallObserver {
- private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
- @Override
- public void onUserActionRequired(Intent intent) {
- PackageInstallObserver.this.onUserActionRequired(intent);
- }
-
- @Override
- public void onPackageInstalled(String basePackageName, int returnCode,
- String msg, Bundle extras) {
- PackageInstallObserver.this.onPackageInstalled(basePackageName, returnCode, msg,
- extras);
- }
- };
-
- /** {@hide} */
- public IPackageInstallObserver2 getBinder() {
- return mBinder;
- }
-
- public void onUserActionRequired(Intent intent) {
- }
-
- public void onPackageInstalled(String basePackageName, int returnCode, String msg,
- Bundle extras) {
- }
- }
其中,当 APK 安装结束时,系统会回调 onPackageInstalled() 接口通知用户当前 APK 安装的结果信息。
接着分析 APK 安装的流程,系统会调用 PKMS 的 installPackageAsUser() 接口,将安装流程带入到 PKMS 中:
- @Override
- public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
- int installFlags, String installerPackageName, int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
-
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */, "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 {
- // Caller holds INSTALL_PACKAGES permission, so we're less strict
- // about installerPackageName.
-
- installFlags &= ~PackageManager.INSTALL_FROM_ADB;
- installFlags &= ~PackageManager.INSTALL_ALL_USERS;
- }
-
- UserHandle user;
- if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {//如果带有ISNASLL_ALL_USERS标记,则给所有用户安装
- 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");
- }
-
- final File originFile = new File(originPath);
- final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
-
- final Message msg = mHandler.obtainMessage(INIT_COPY);//要发送INIT_COPY消息,开始拷贝需要安装的Apk
-
- final VerificationInfo verificationInfo = new VerificationInfo(
- null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
-
- //将安装参数信息保存到InstallParams对象中
- final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
- installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
- null /*packageAbiOverride*/, null /*grantedPermissions*/,
- null /*certificates*/);
- params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
- msg.obj = params;
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
- System.identityHashCode(msg.obj));
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(msg.obj));
-
- mHandler.sendMessage(msg);//发送消息到PackageHandler中
- }
首先是一些安装权限检查,之后会创建一个 InstallParams 实例,它里面封装了此次安装 APK 的各项参数。接着会发送INIT_COPY 消息到 Handler 进行处理。
这些类型的作用就是封装一次应用安装过程的一些基本信息,我们只要注意它们的使用场景即可。INIT_COPY 消息会触发 APK 文件的拷贝动作,它会由 PMS::PackageHandler 接收,而 PackageHandler 在 PkMS 初始化时会被创建。PackageHandler 主要负责这些 APK 安装消息的接收处理,我们先看 INIT_COPY 消息的处理过程:
- case INIT_COPY: {
- HandlerParams params = (HandlerParams) msg.obj;//获取Apk安装参数
- int idx = mPendingInstalls.size();//mPendingInstalls保存所有的需要安装的APk的安装信息
- if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
- // If a bind was already initiated we dont really
- // need to do anything. The pending install
- // will be processed later on.
- if (!mBound) {
- // 如果没有绑定DefaultContainerService服务;服务连接成功后,会置为true
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
- System.identityHashCode(mHandler));
- // If this is the only one pending we might
- // have to bind to the service again.
- if (!connectToService()) {
- // 异步过程.去绑定DefaultContainerService服务,绑定失败,需要报告错误信息;绑定成功后,会发送MCS_BOUND消息
- Slog.e(TAG, "Failed to bind to media container service");
- params.serviceError();
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
- System.identityHashCode(mHandler));
- if (params.traceMethod != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
- params.traceCookie);
- }
- return;
- } else {
- // 绑定服务成功后,将当前的安装参数请求保存到mPendingInstalls
- // Once we bind to the service, the first
- // pending request will be processed.
- mPendingInstalls.add(idx, params);
- }
- } else {
- mPendingInstalls.add(idx, params);
- // 服务已经绑定,也会将安装信息保存到mPendingInstalls中
- // Already bound to the service. Just make
- // sure we trigger off processing the first request.
- if (idx == 0) {//如果mPendingInstalls中只有一项内容,则立即发送MCS_BOUND消息
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- }
- break;
- }
mPendingInstalls 是 PackageHandler 的一个成员,它保存所有的 APK 安装的 InstallParams 对象。mBound 标识当前有没有绑定 DefaultContainerService 服务,之后的安装流程会调用它的一些方法。绑定 DCS 服务的处理由 PackageHandler::connectToService() 函数提供:
- static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
- DEFAULT_CONTAINER_PACKAGE,
- "com.android.defcontainer.DefaultContainerService");
-
- final private DefaultContainerConnection mDefContainerConn =
- new DefaultContainerConnection();
- 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");
- }
- }
-
- private boolean connectToService() {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
- " DefaultContainerService");
- Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- if (mContext.bindServiceAsUser(service, mDefContainerConn,
- Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- mBound = true;
- return true;
- }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- return false;
- }
如果服务绑定成功,mBound 会置为 true,并会发送 MCS_BOUND 消息,并附带 DCS 服务的 Binder 实例发送给PackageHandler。接着看 MCS_BOUND 消息的处理:
- case MCS_BOUND: {
- if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
- if (msg.obj != null) {
- mContainerService = (IMediaContainerService) msg.obj;//DefaultContainerService服务的代理
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
- System.identityHashCode(mHandler));
- }
- if (mContainerService == null) {
- if (!mBound) {
- // 如果服务没有连接成功,则需要报告错误
- // Something seriously wrong since we are not bound and we are not
- // waiting for connection. Bail out.
- Slog.e(TAG, "Cannot bind to media container service");
- for (HandlerParams params : mPendingInstalls) {
- // Indicate service bind error
- params.serviceError();
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
- if (params.traceMethod != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
- params.traceMethod, params.traceCookie);
- }
- return;
- }
- mPendingInstalls.clear();//情况mPendingInstalls
- } else {
- Slog.w(TAG, "Waiting to connect to media container service");
- }
- } else if (mPendingInstalls.size() > 0) {//DefaultContainerService服务连接正常
- HandlerParams params = mPendingInstalls.get(0);//从首部拿出需要执行的安装参数信息
- if (params != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
- if (params.startCopy()) {
- // 调用HandlerParrams接口,去执行apk的拷贝工作;此处是调用HandlerParrams::startCopy()
- // We are done... look for more work or to
- // go idle.
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Checking for more work or unbind...");
- // Delete pending install
- if (mPendingInstalls.size() > 0) {
- //工作完成,移除mPendingInstalls首部内容,因为我们是从首部开始执行的
- mPendingInstalls.remove(0);
- }
- if (mPendingInstalls.size() == 0) {
- //如果mPendingInstalls已经没有内容,说明安装任务已经全部执行完毕,则会延迟10s后断开服务连接
- if (mBound) {
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Posting delayed MCS_UNBIND");
- removeMessages(MCS_UNBIND);
- Message ubmsg = obtainMessage(MCS_UNBIND);
- // Unbind after a little delay, to avoid
- // continual thrashing.
- sendMessageDelayed(ubmsg, 10000);
- }
- } else {//否则,会再次发送MCS_BOUND消息,处理下一个安装请求
- // There are more pending requests in queue.
- // Just post MCS_BOUND message to trigger processing
- // of next pending install.
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Posting MCS_BOUND for next work");
- mHandler.sendEmptyMessage(MCS_BOUND);//发送消息,处理下一个安装请求
- }
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- } else {
- // Should never happen ideally.
- Slog.w(TAG, "Empty queue");
- }
- break;
- }
mContainerService 对象保存了 DefaultContainerService 服务的 Binder 实例,它将被用来调用一些该服务中提供的方法。
如果该实例为空,则表明服务连接异常,则需要对外报告错误,并清空 mPendingInstalls 集合;如果非空,则要处理 APK 的安装请求:
因为传入的安装参数对象是 InstallParams,我们直接看它父类的 HandlerParams::startCopy() 函数:
- final boolean startCopy() {
- boolean res;
- try {
- if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
-
- if (++mRetries > MAX_RETRIES) {//会尝试安装4次,如果4次都没有安装成功,则会退出
- Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
- mHandler.sendEmptyMessage(MCS_GIVE_UP);//尝试4次后,都没有安装成功,则发送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);//安装出错,则发送消息MCS_RECONNECT消息重新连接
- res = false;
- }
- handleReturnCode();
- return res;
- }
HandlerParams::startCopy() 为 HandlerParams 的子类所共有。首先一次 APK 的安装操作总共会尝试四次,如果四次都安装失败,则会发送 MCS_GIVE_UP 消息,放弃这次安装请求,并调用子类实现的 handleServiceError() 处理错误,然后直接返回;
否则,调用子类实现的 handleStartCopy() 函数进程 copy 流程。handleStartCopy() 处理成功后,还会调用子类实现的handleReturnCode() 处理最后的结果。我们看 InstallParams::handleStartCopy() 的实现:
- public void handleStartCopy() throws RemoteException {
- int ret = PackageManager.INSTALL_SUCCEEDED;
-
- // If we're already staged, we've firmly committed to an install location
- if (origin.staged) {
- if (origin.file != null) {
- installFlags |= PackageManager.INSTALL_INTERNAL;
- installFlags &= ~PackageManager.INSTALL_EXTERNAL;
- } else if (origin.cid != null) {
- installFlags |= PackageManager.INSTALL_EXTERNAL;
- installFlags &= ~PackageManager.INSTALL_INTERNAL;
- } else {
- throw new IllegalStateException("Invalid stage location");
- }
- }
-
- final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
- final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
- final boolean ephemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
- PackageInfoLite pkgLite = null;
-
- if (onInt && onSd) {//如果既有安装在内部的标志,又有安装SD卡上的标志,则设置错误返回
- // Check if both bits are set.
- Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else if (onSd && ephemeral) {//此处与上述类似
- Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external");
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else {
- pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
- packageAbiOverride);//获取安装包包含有应用信息的PacageInfoLite对象
-
- if (DEBUG_EPHEMERAL && ephemeral) {
- Slog.v(TAG, "pkgLite for install: " + pkgLite);
- }
-
- /*
- * If we have too little free space, try to free cache
- * before giving up.
- */
- //如果安装的位置空间不够,会先尝试清除cache空间
- if (!origin.staged && pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
- // TODO: focus freeing disk space on the target device
- final StorageManager storage = StorageManager.from(mContext);
- final long lowThreshold = storage.getStorageLowBytes(
- Environment.getDataDirectory());
-
- final long sizeBytes = mContainerService.calculateInstalledSize(
- origin.resolvedPath, isForwardLocked(), packageAbiOverride);
-
- try {
- mInstaller.freeCache(null, sizeBytes + lowThreshold);
- pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
- installFlags, packageAbiOverride);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to free cache", e);
- }
-
- /*
- * The cache free must have deleted the file we
- * downloaded to install.
- *
- * TODO: fix the "freeCache" call to not delete
- * the file we care about.
- */
- if (pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
- pkgLite.recommendedInstallLocation
- = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
- }
- }
- }
-
- if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果该标志位依然是INSTALL_SUCCEEDED,则说明前面的校验都通过
- int loc = pkgLite.recommendedInstallLocation;
- if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
- ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
- ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
- ret = PackageManager.INSTALL_FAILED_INVALID_APK;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
- ret = PackageManager.INSTALL_FAILED_INVALID_URI;
- } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
- ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
- } else {
- // Override with defaults if needed.
- loc = installLocationPolicy(pkgLite);
- if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
- ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
- } else if (!onSd && !onInt) {
- // Override install location with flags
- if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
- // Set the flag to install on external media.
- installFlags |= PackageManager.INSTALL_EXTERNAL;
- installFlags &= ~PackageManager.INSTALL_INTERNAL;
- } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
- if (DEBUG_EPHEMERAL) {
- Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
- }
- installFlags |= PackageManager.INSTALL_EPHEMERAL;
- installFlags &= ~(PackageManager.INSTALL_EXTERNAL
- |PackageManager.INSTALL_INTERNAL);
- } else {
- // Make sure the flag for installing on external
- // media is unset
- installFlags |= PackageManager.INSTALL_INTERNAL;
- installFlags &= ~PackageManager.INSTALL_EXTERNAL;
- }
- }
- }
- }
-
- final InstallArgs args = createInstallArgs(this);//函数中会有分支处理,这里考虑FileInstallArgs实例创建情况,并会保存一份到InstallParams::mArgs
- mArgs = args;
-
- if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果该标志位依然是INSTALL_SUCCEEDED,则说明前面的校验都通过
- // TODO: http://b/22976637
- // Apps installed for "all" users use the device owner to verify the app
- UserHandle verifierUser = getUser();
- if (verifierUser == UserHandle.ALL) {
- verifierUser = UserHandle.SYSTEM;
- }
-
- /*
- * Determine if we have any installed package verifiers. If we
- * do, then we'll defer to them to verify the packages.
- */
- final int requiredUid = mRequiredVerifierPackage == null ? -1
- : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
- verifierUser.getIdentifier());
- //if部分是一段执行应用校验的代码,如果需要校验,则通过向系统中所有带有校验功能的组件发送Intent.ACTION_PACKAGE_NEEDS_VERIFICATION广播来完成
- if (!origin.existing && requiredUid != -1
- && isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) {
- final Intent verification = new Intent(
- Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
- verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
- PACKAGE_MIME_TYPE);
- verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- // Query all live verifiers based on current user state
- final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
- PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
-
- if (DEBUG_VERIFY) {
- Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
- + verification.toString() + " with " + pkgLite.verifiers.length
- + " optional verifiers");
- }
-
- final int verificationId = mPendingVerificationToken++;
-
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
-
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
- installerPackageName);
-
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
- installFlags);
-
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
- pkgLite.packageName);
-
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
- pkgLite.versionCode);
-
- if (verificationInfo != null) {
- if (verificationInfo.originatingUri != null) {
- verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
- verificationInfo.originatingUri);
- }
- if (verificationInfo.referrer != null) {
- verification.putExtra(Intent.EXTRA_REFERRER,
- verificationInfo.referrer);
- }
- if (verificationInfo.originatingUid >= 0) {
- verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
- verificationInfo.originatingUid);
- }
- if (verificationInfo.installerUid >= 0) {
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
- verificationInfo.installerUid);
- }
- }
-
- final PackageVerificationState verificationState = new PackageVerificationState(
- requiredUid, args);
-
- mPendingVerification.append(verificationId, verificationState);
-
- final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
- receivers, verificationState);
-
- /*
- * If any sufficient verifiers were listed in the package
- * manifest, attempt to ask them.
- */
- if (sufficientVerifiers != null) {
- final int N = sufficientVerifiers.size();
- if (N == 0) {
- Slog.i(TAG, "Additional verifiers required, but none installed.");
- ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
- } else {
- for (int i = 0; i < N; i++) {
- final ComponentName verifierComponent = sufficientVerifiers.get(i);
-
- final Intent sufficientIntent = new Intent(verification);
- sufficientIntent.setComponent(verifierComponent);
- mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
- }
- }
- }
-
- final ComponentName requiredVerifierComponent = matchComponentForVerifier(
- mRequiredVerifierPackage, receivers);
- if (ret == PackageManager.INSTALL_SUCCEEDED
- && mRequiredVerifierPackage != null) {
- Trace.asyncTraceBegin(
- TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
- /*
- * Send the intent to the required verification agent,
- * but only start the verification timeout after the
- * target BroadcastReceivers have run.
- */
- verification.setComponent(requiredVerifierComponent);
- mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final Message msg = mHandler
- .obtainMessage(CHECK_PENDING_VERIFICATION);
- msg.arg1 = verificationId;
- mHandler.sendMessageDelayed(msg, getVerificationTimeout());
- }
- }, null, 0, null, null);
-
- /*
- * We don't want the copy to proceed until verification
- * succeeds, so null out this field.
- */
- mArgs = null;
- }
- } else {//不需要校验,则调用FileInstallArgs::copyApk()继续后续的处理
- /*
- * No package verification is enabled, so immediately start
- * the remote call to initiate copy using temporary file.
- */
- ret = args.copyApk(mContainerService, true);
- }
- }
-
- mRet = ret;
- }
这里总结下这段代码处理:
接着看 FileInstallArgs::copyApk() 函数:
- private int doCopyApk(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 {
- final boolean isEphemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
- final File tempDir =
- mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//通过PackageInstallService在/data/app/下生成临时文件
- codeFile = tempDir;
- resourceFile = tempDir;
- } catch (IOException e) {
- Slog.w(TAG, "Failed to create copy file: " + e);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
-
-
- //为临时文件目录创建ParcelFileDescriptor描述符,它能在Binder间传递
- final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
- @Override
- public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
- if (!FileUtils.isValidExtFilename(name)) {
- throw new IllegalArgumentException("Invalid filename: " + name);
- }
- try {
- final File file = new File(codeFile, name);
- final FileDescriptor fd = Os.open(file.getAbsolutePath(),
- O_RDWR | O_CREAT, 0644);
- Os.chmod(file.getAbsolutePath(), 0644);
- return new ParcelFileDescriptor(fd);
- } catch (ErrnoException e) {
- throw new RemoteException("Failed to open: " + e.getMessage());
- }
- }
- };
-
- int ret = PackageManager.INSTALL_SUCCEEDED;
-
- //使用DefaultContainerService::copyPackage()方法执行apk文件的复制
- ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to copy package");
- return ret;
- }
-
- //安装应用中存在的native动态库,主要是从Apk打包文件中将它们提取出来放置
- 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;
- }
这里的处理有如下几个:
- @Deprecated
- public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
- synchronized (mSessions) {
- try {
- final int sessionId = allocateSessionIdLocked();
- mLegacySessions.put(sessionId, true);
- final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
- prepareStageDir(stageDir);
- return stageDir;
- } catch (IllegalStateException e) {
- throw new IOException(e);
- }
- }
- }
-
- private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
- final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
- return new File(stagingDir, "vmdl" + sessionId + ".tmp");
- }
临时文件的名称格式大致是:'vmdl-随机数.tmp' 的形式。如果一切过程都正常,至此,APK 安装的第一部分的工作:APK 文件的拷贝,就结束了。根据前面的流程,最后会调用 InstallParams::handleReturnCode() 执行返回结果的处理:
- @Override
- 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);
- }
- }
因为 InstallParams::mArgs 我们之前赋值过,所以肯定不为空,继续调用 processPendingInstall() 函数:
- 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.setReturnCode(currentStatus);
- res.uid = -1;
- res.pkg = null;
- res.removedInfo = null;
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果之前的处理顺利完成
- args.doPreInstall(res.returnCode);
- synchronized (mInstallLock) {
- installPackageTracedLI(args, res);//则需要去解析、装载应用
- }
- args.doPostInstall(res.returnCode, res.uid);
- }
-
- // A restore should be performed at this point if (a) the install
- // succeeded, (b) the operation is not an update, and (c) the new
- // package has not opted out of backup participation.
- //后面一段都在执行备份操作
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
- final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
- boolean doRestore = !update
- && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
-
- // Set up the post-install work request bookkeeping. This will be used
- // and cleaned up by the post-install event handling regardless of whether
- // there's a restore pass performed. Token values are >= 1.
- int token;
- if (mNextInstallToken < 0) mNextInstallToken = 1;
- token = mNextInstallToken++;
-
- PostInstallData data = new PostInstallData(args, res);
- mRunningInstalls.put(token, data);
- if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
-
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
- // Pass responsibility to the Backup Manager. It will perform a
- // restore if appropriate, then pass responsibility back to the
- // Package Manager to run the post-install observer callbacks
- // and broadcasts.
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (bm != null) {
- if (DEBUG_INSTALL) Log.v(TAG, "token " + token
- + " to BM for possible restore");
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- try {
- // TODO: http://b/22388012
- if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
- bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
- } else {
- doRestore = false;
- }
- } catch (RemoteException e) {
- // can't happen; the backup manager is local
- } catch (Exception e) {
- Slog.e(TAG, "Exception trying to enqueue restore", e);
- doRestore = false;
- }
- } else {
- Slog.e(TAG, "Backup Manager not found!");
- doRestore = false;
- }
- }
-
- if (!doRestore) {//直接去处理安装请求
- // No restore possible, or the Backup Manager was mysteriously not
- // available -- just fire the post-install work request directly.
- if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
-
- Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);//此处发送POST_INSTALL消息,继续处理流程
- mHandler.sendMessage(msg);
- }
- }
- });
- }
函数内会调用 FileInstallArgs 的 doPreInstall()/doPostInstall() 函数进行一些清理工作。其中 PMS::installPackageTracedLI() 函数的主要功能就是将当前安装的 APK 加入到它的管理体系中,以便之后统一管理;特殊的,该函数内部会调用 FileInstallArgs::doReanme() 函数将之前的 APK 备份文件重命名。具体的实现是扫描 APK 的过程,这部分之前已经有介绍过。
略去之后的备份工作后,最后会发送 POST_INSTALL 消息,依旧是 PackageHandler 处理:
- case POST_INSTALL: {//应用安装的收尾处理:主要动作是发送广播,通知系统中其他应用,开始某些处理工作:如果Launcher添加应用图标等
- if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
-
- PostInstallData data = mRunningInstalls.get(msg.arg1);
- final boolean didRestore = (msg.arg2 != 0);
- mRunningInstalls.delete(msg.arg1);
-
- if (data != null) {
- InstallArgs args = data.args;
- PackageInstalledInfo parentRes = data.res;
-
- final boolean grantPermissions = (args.installFlags
- & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
- final boolean killApp = (args.installFlags
- & PackageManager.INSTALL_DONT_KILL_APP) == 0;
- final String[] grantedPermissions = args.installGrantPermissions;
-
- // Handle the parent package
- handlePackagePostInstall(parentRes, grantPermissions, killApp,
- grantedPermissions, didRestore, args.installerPackageName,
- args.observer);//各种广播的发送处理
-
- // Handle the child packages
- final int childCount = (parentRes.addedChildPackages != null)
- ? parentRes.addedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
- handlePackagePostInstall(childRes, grantPermissions, killApp,
- grantedPermissions, false, args.installerPackageName,
- args.observer);
- }
-
- // Log tracing if needed
- if (args.traceMethod != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
- args.traceCookie);
- }
- } else {
- Slog.e(TAG, "Bogus post-install token " + msg.arg1);
- }
-
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
- } break;
由于需要安装的 APK 文件已经拷贝到了系统中,并且 PKMS 也已经对它进行了统一管理,到此 APK 的安装工作就基本完成了。
但是,此时系统其它组件并不知道此时有新的 APK 安装进了系统中,所以这里需要发送一些广播给感兴趣的接收者,通知它们当前有新的 APK 安装完成了。这一部分最明显的就是 Launcher 了,我们安装 APK 后,Launcher 上要添加图标,就是根据这部分内容来的。发送广播的主要函数是 handlePackagePostInstall(),它的实现如下:
- private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
- boolean killApp, String[] grantedPermissions,
- boolean launchedForRestore, String installerPackage,
- IPackageInstallObserver2 installObserver) {
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- // Send the removed broadcasts
- if (res.removedInfo != null) {
- res.removedInfo.sendPackageRemovedBroadcasts(killApp);
- }
-
- // Now that we successfully installed the package, grant runtime
- // permissions if requested before broadcasting the install.
- if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
- >= Build.VERSION_CODES.M) {
- grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
- }
-
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
-
- // If this is the first time we have child packages for a disabled privileged
- // app that had no children, we grant requested runtime permissions to the new
- // children if the parent on the system image had them already granted.
- if (res.pkg.parentPackage != null) {
- synchronized (mPackages) {
- grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
- }
- }
-
- synchronized (mPackages) {
- mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
- }
-
- final String packageName = res.pkg.applicationInfo.packageName;
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, res.uid);
-
- int[] firstUsers = EMPTY_INT_ARRAY;
- int[] updateUsers = EMPTY_INT_ARRAY;
- if (res.origUsers == null || res.origUsers.length == 0) {
- firstUsers = res.newUsers;
- } else {
- for (int newUser : res.newUsers) {
- boolean isNew = true;
- for (int origUser : res.origUsers) {
- if (origUser == newUser) {
- isNew = false;
- break;
- }
- }
- if (isNew) {
- firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
- } else {
- updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
- }
- }
- }
-
- // Send installed broadcasts if the install/update is not ephemeral
- if (!isEphemeral(res.pkg)) {
- mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
-
- // Send added for users that see the package for the first time
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/, null /*targetPackage*/,
- null /*finishedReceiver*/, firstUsers);//首先要发送Intent.ACTION_PACKAGE_ADDED广播,表明系统中有新的apk被安装了
-
- // Send added for users that don't see the package for the first time
- if (update) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/, null /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
-
- // Send replaced for users that don't see the package for the first time
- if (update) {//如果当前安装是升级,则还需要发送更多的广播:Intent.ACTION_PACKAGE_REPLACED/Intent.ACTION_MY_PACKAGE_REPLACED
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/,
- updateUsers);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null /*package*/, null /*extras*/, 0 /*flags*/,
- packageName /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
- } else if (launchedForRestore && !isSystemApp(res.pkg)) {
- // First-install and we did a restore, so we're responsible for the
- // first-launch broadcast.
- if (DEBUG_BACKUP) {
- Slog.i(TAG, "Post-restore of " + packageName
- + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
- }
- sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
- }
-
- // Send broadcast package appeared if forward locked/external for all users
- // treat asec-hosted packages like removable media on upgrade
- if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {//如果安装的是foreword lock应用或是安装在SD卡上的应用,也有相关的广播要发送
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + res.pkg
- + " is ASEC-hosted -> AVAILABLE");
- }
- final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
- ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(packageName);
- sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
- }
- }
-
- // Work that needs to happen on first install within each user
- if (firstUsers != null && firstUsers.length > 0) {
- synchronized (mPackages) {
- for (int userId : firstUsers) {
- if (packageIsBrowser(packageName, userId)) {
- mSettings.setDefaultBrowserPackageNameLPw(null, userId);
- }
-
- mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
- }
- }
- }
-
- EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
- getUnknownSourcesSettings());
-
- Runtime.getRuntime().gc();
-
- if (res.removedInfo != null && res.removedInfo.args != null) {
- synchronized (mInstallLock) {
- res.removedInfo.args.doPostDeleteLI(true);
- }
- }
- }
-
- if (installObserver != null) {//回调接口调用,反馈最终安装的结果
- try {
- Bundle extras = extrasForInstallResult(res);
- installObserver.onPackageInstalled(res.name, res.returnCode,
- res.returnMsg, extras);
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
- }
主要处理就是发送各种广播,比如:
分析到这里,一个 APK 的安装过程就简要地分析完成了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。