当前位置:   article > 正文

Androidapk安装流程之adb安装

install requires an argument
image.png

目录

Android apk安装流程之adb安装

app安装方式

Android应用程序安装有四种方式:

  1. 系统启动时安装,没有安装界面
  2. 第三方应用安装,有安装界面,也是我们最熟悉的方式
  3. ADB命令安装,没有安装界面
  4. 通过Google Play市场安装,没有安装界面

四种方式最后都是通过PackageManagerService服务来完成应用程序的安装。

PackageManagerService服务通过与Installd服务通信,发送具体的指令来执行应用程序的安装、卸载等工作。

image.png

使用路径

app在安装时涉及到如下几个重要目录:

目录解释
system/app系统应用程序的目录
data/app用户程序安装的目录
data/data存放应用程序数据的目录
data/dalvik-cache存放的是经过优化的dex文件

APK文件结构

目录描述
assert存放的原生资源文件,通过AssetManager类访问
libnative库文件
META-INF存放签名信息,用来保证APK包的完整性和系统的安全。系统安装APK时,应用管理器会按照对应算法对包里文件做校验,如果校验结果与META-INF中内容不一致,则不会安装这个APK。
res种资源文件系统会在R.java里面自动生成该资源文件的ID,所以访问这种资源文件比较简单,通过R.XXX.ID即可
AndroidManifest.xml每个应用都必须定义和包含,描述应用的名字、版本权限、引用的库文件等信息。apk中的AndroidManifest.xml经过压缩,可以通过AXMLPrinter2工具解开。
classes.dex是JAVA源码编译后生成的JAVA字节码文件。但Android使用的dalvik虚拟机与标准的JAVA虚拟机不兼容,dex文件与class文件相比,不论是文件结构还是opcode都不一样。
resources.arsc编译后的二进制资源文件。

应用程序安装过程

  1. adb install:
    安装入口函数为Pm.runInstall
    frameworks\base\cmds\pm\src\com\android\commands\pm\Pm.java

  2. 网络下载应用安装和第三方应用安装:
    安装入口函数为ApplicationPackageManager.installPackage
    frameworks\base\core\java\android\app\ApplicationPackageManager.java

apk安装的四大步骤:1. 拷贝apk到指定的目录:默认情况下,用户安装的apk首先会拷贝到/data/app下,用户有访问/data/app目录的权限,但系统出厂的apk文件会被放到/system分区下,包括/system/app,/system/vendor/app,以及/system/priv-app等,该分区需要root权限的用户才能访问。2. 加载apk、拷贝文件、创建应用的数据目录:为了加快APP的启动速度,apk在安装的时候,会首先将APP的可执行文件(dex)拷贝到/data/dalvik-cache目录下,缓存起来。再在/data/data/目录下创建应用程序的数据目录(以应用包名命令),用来存放应用的数据库、xml文件、cache、二进制的so动态库等。3. 解析apk的AndroidManifest.xml文件:在安装apk的过程中,会解析apk的AndroidManifest.xml文件,将apk的权限、应用包名、apk的安装位置、版本、userID等重要信息保存在/data/system/packages.xml文件中。这些操作都是在PackageManagerService中完成的。4. 显示icon图标:应用程序经过PMS中的逻辑处理后,相当于已经注册好了,如果想要在Android桌面上看到icon图标,则需要Launcher将系统中已经安装的程序展现在桌面上。

adb install 的安装方式

adb install 的安装方式,会调用| commandline.cpp |
中的adb_commandline函数:

  1. int adb_commandline(int argc, const char** argv) {
  2. ……
  3. else if (!strcmp(argv[0], "install")) {
  4. if (argc < 2) return usage("install requires an argument");
  5. if (_use_legacy_install()) {
  6. return install_app_legacy(transport_type, serial, argc, argv);
  7. }
  8. return install_app(transport_type, serial, argc, argv);
  9. }
  10. ……
  11. return 1;
  12. }

adb会把apk文件copy到data/local/tmp/目录下,然后向shell服务发送pm命令安装apk,最后调用Pm.runInstall()方法来安装apk。

  1. static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
  2. static const char *const DATA_DEST = "/data/local/tmp/%s";
  3. static const char *const SD_DEST = "/sdcard/tmp/%s";
  4. const char* where = DATA_DEST;
  5. ……
  6. int result = -1;
  7. std::vector<const char*> apk_file = {argv[last_apk]};
  8. std::string apk_dest = android::base::StringPrintf(
  9. where, android::base::Basename(argv[last_apk]).c_str());
  10. // 复制app到/data/local/tmp/
  11. if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
  12. argv[last_apk] = apk_dest.c_str();
  13. //执行pm命令
  14. result = pm_command(transport, serial, argc, argv);
  15. cleanup_apk:
  16. delete_file(transport, serial, apk_dest);
  17. return result;
  18. }

最后进入到Pm.runInstall()函数来安装apk。

Pm.java中的runInstall函数:

  1. private int runInstall() throws RemoteException {
  2. long startedTime = SystemClock.elapsedRealtime();
  3. final InstallParams params = makeInstallParams();
  4. final String inPath = nextArg();
  5. if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
  6. File file = new File(inPath);
  7. if (file.isFile()) {
  8. try {
  9. // 使用PackageParser解析apk包
  10. ApkLite baseApk = PackageParser.parseApkLite(file, 0);
  11. PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
  12. null, null);
  13. params.sessionParams.setSize(
  14. PackageHelper.calculateInstalledSize(pkgLite, false,
  15. params.sessionParams.abiOverride));
  16. } catch (PackageParserException | IOException e) {
  17. System.err.println("Error: Failed to parse APK file: " + e);
  18. return 1;
  19. }
  20. } else {
  21. System.err.println("Error: Can't open non-file: " + inPath);
  22. return 1;
  23. }
  24. }
  25. // 创建Session
  26. final int sessionId = doCreateSession(params.sessionParams,
  27. params.installerPackageName, params.userId);
  28. try {
  29. if (inPath == null && params.sessionParams.sizeBytes == -1) {
  30. System.err.println("Error: must either specify a package size or an APK file");
  31. return 1;
  32. }
  33. // 写入Session
  34. if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
  35. false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
  36. return 1;
  37. }
  38. // 提交Session
  39. Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
  40. if (status.second != PackageInstaller.STATUS_SUCCESS) {
  41. return 1;
  42. }
  43. Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()
  44. - startedTime) + " ms");
  45. System.out.println("Success");
  46. return 0;
  47. } finally {
  48. try {
  49. mInstaller.abandonSession(sessionId);
  50. } catch (Exception ignore) {
  51. }
  52. }
  53. }

runInstall主要进行了三件事,创建session、对session进行写操作,最后提交session。

doCreateSession函数调用的是PackageInstallerService的createSession,这个过程主要是为APK安装做好准备工作,例如权限检查、目的临时文件的创建等, 最终创建出PackageInstallerSession对象。

PackageInstallerSession可以看做是”安装APK”这个请求的封装,其中包含了处理这个请求需要的一些信息。实际上PackageInstallerSession不仅是分装请求的对象,其自身还是个服务端。
doCreateSession函数:

  1. private int doCreateSession(SessionParams params, String installerPackageName, int userId)
  2. throws RemoteException {
  3. userId = translateUserId(userId, "runInstallCreate");
  4. if (userId == UserHandle.USER_ALL) {
  5. userId = UserHandle.USER_SYSTEM;
  6. params.installFlags |= PackageManager.INSTALL_ALL_USERS;
  7. }
  8. final int sessionId = mInstaller.createSession(params, installerPackageName, userId);
  9. return sessionId;
  10. }
  11. mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
  12. mInstaller = mPm.getPackageInstaller();

进入PackageManagerService.java类看一下getPackageInstaller函数:

  1. public IPackageInstaller getPackageInstaller() {
  2. if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
  3. return null;
  4. }
  5. return mInstallerService;
  6. }
  7. final PackageInstallerService mInstallerService;
  8. mInstallerService = new PackageInstallerService(context, this);

所以最后获取了PackageInstallerService对象,并执行createSession函数:

  1. public int createSession(SessionParams params, String installerPackageName, int userId) {
  2. try {
  3. return createSessionInternal(params, installerPackageName, userId);
  4. } catch (IOException e) {
  5. throw ExceptionUtils.wrap(e);
  6. }
  7. }
  8. private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
  9. throws IOException {
  10. // 权限检查
  11. final int callingUid = Binder.getCallingUid();
  12. mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
  13. if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
  14. throw new SecurityException("User restriction prevents installing");
  15. }
  16. ……
  17. // 获取图标数据
  18. if (params.appIcon != null) {
  19. final ActivityManager am = (ActivityManager) mContext.getSystemService(
  20. Context.ACTIVITY_SERVICE);
  21. final int iconSize = am.getLauncherLargeIconSize();
  22. if ((params.appIcon.getWidth() > iconSize * 2)
  23. || (params.appIcon.getHeight() > iconSize * 2)) {
  24. params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
  25. true);
  26. }
  27. }
  28. ……
  29. final long createdMillis = System.currentTimeMillis();
  30. //创建文件夹
  31. File stageDir = null;
  32. String stageCid = null;
  33. if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
  34. final boolean isInstant =
  35. (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
  36. stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
  37. } else {
  38. stageCid = buildExternalStageCid(sessionId);
  39. }
  40. // 创建session
  41. session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
  42. mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
  43. params, createdMillis, stageDir, stageCid, false, false);
  44. synchronized (mSessions) {
  45. mSessions.put(sessionId, session);
  46. }
  47. mCallbacks.notifySessionCreated(session.sessionId, session.userId);
  48. writeSessionsAsync();
  49. return sessionId;
  50. }

之后开始进入doWriteSession函数:

  1. private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
  2. boolean logSuccess) throws RemoteException {
  3. if (STDIN_PATH.equals(inPath)) {
  4. inPath = null;
  5. } else if (inPath != null) {
  6. final File file = new File(inPath);
  7. if (file.isFile()) {
  8. sizeBytes = file.length();
  9. }
  10. }
  11. final SessionInfo info = mInstaller.getSessionInfo(sessionId);
  12. PackageInstaller.Session session = null;
  13. InputStream in = null;
  14. OutputStream out = null;
  15. try {
  16. session = new PackageInstaller.Session(
  17. mInstaller.openSession(sessionId));
  18. if (inPath != null) {
  19. in = new FileInputStream(inPath);
  20. } else {
  21. in = new SizedInputStream(System.in, sizeBytes);
  22. }
  23. out = session.openWrite(splitName, 0, sizeBytes);
  24. int total = 0;
  25. byte[] buffer = new byte[65536];
  26. int c;
  27. while ((c = in.read(buffer)) != -1) {
  28. total += c;
  29. out.write(buffer, 0, c);
  30. if (info.sizeBytes > 0) {
  31. final float fraction = ((float) c / (float) info.sizeBytes);
  32. session.addProgress(fraction);
  33. }
  34. }
  35. session.fsync(out);
  36. if (logSuccess) {
  37. System.out.println("Success: streamed " + total + " bytes");
  38. }
  39. return PackageInstaller.STATUS_SUCCESS;
  40. } catch (IOException e) {
  41. System.err.println("Error: failed to write; " + e.getMessage());
  42. return PackageInstaller.STATUS_FAILURE;
  43. } finally {
  44. IoUtils.closeQuietly(out);
  45. IoUtils.closeQuietly(in);
  46. IoUtils.closeQuietly(session);
  47. }
  48. }

该函数通过PackageInstallerSession将/data/local/tmp的apk拷贝到终端目录内

最后开始执行doCommitSession函数:

  1. private Pair<String, Integer> doCommitSession(int sessionId, boolean logSuccess)
  2. throws RemoteException {
  3. PackageInstaller.Session session = null;
  4. try {
  5. // 获取session
  6. session = new PackageInstaller.Session(
  7. mInstaller.openSession(sessionId));
  8. final LocalIntentReceiver receiver = new LocalIntentReceiver();
  9. // 执行session的commit函数
  10. session.commit(receiver.getIntentSender());
  11. final Intent result = receiver.getResult();
  12. final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
  13. PackageInstaller.STATUS_FAILURE);
  14. if (status == PackageInstaller.STATUS_SUCCESS) {
  15. if (logSuccess) {
  16. System.out.println("Success");
  17. }
  18. } else {
  19. System.err.println("Failure ["
  20. + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
  21. }
  22. return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status);
  23. } finally {
  24. IoUtils.closeQuietly(session);
  25. }
  26. }

跟踪下PackageInstaller.java中的session的commit函数:

  1. public static class Session implements Closeable {
  2. private IPackageInstallerSession mSession;
  3. public void commit(@NonNull IntentSender statusReceiver) {
  4. try {
  5. mSession.commit(statusReceiver);
  6. } catch (RemoteException e) {
  7. throw e.rethrowFromSystemServer();
  8. }
  9. }
  10. }

执行进入PackageInstallerSession.java类中的commit函数:

  1. public void commit(IntentSender statusReceiver) {
  2. Preconditions.checkNotNull(statusReceiver);
  3. final boolean wasSealed;
  4. synchronized (mLock) {
  5. wasSealed = mSealed;
  6. if (!mSealed) {
  7. for (RevocableFileDescriptor fd : mFds) {
  8. if (!fd.isRevoked()) {
  9. throw new SecurityException("Files still open");
  10. }
  11. }
  12. for (FileBridge bridge : mBridges) {
  13. if (!bridge.isClosed()) {
  14. throw new SecurityException("Files still open");
  15. }
  16. }
  17. mSealed = true;
  18. }
  19. mClientProgress = 1f;
  20. computeProgressLocked(true);
  21. }
  22. if (!wasSealed) {
  23. mCallback.onSessionSealedBlocking(this);
  24. }
  25. mActiveCount.incrementAndGet();
  26. final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
  27. statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
  28. mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
  29. }

函数中发送消息MSG_COMMIT:

  1. private final Handler.Callback mHandlerCallback = new Handler.Callback() {
  2. @Override
  3. public boolean handleMessage(Message msg) {
  4. final PackageInfo pkgInfo = mPm.getPackageInfo(
  5. params.appPackageName, PackageManager.GET_SIGNATURES
  6. | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
  7. final ApplicationInfo appInfo = mPm.getApplicationInfo(
  8. params.appPackageName, 0, userId);
  9. synchronized (mLock) {
  10. if (msg.obj != null) {
  11. mRemoteObserver = (IPackageInstallObserver2) msg.obj;
  12. }
  13. try {
  14. commitLocked(pkgInfo, appInfo);
  15. } catch (PackageManagerException e) {
  16. final String completeMsg = ExceptionUtils.getCompleteMessage(e);
  17. Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
  18. destroyInternal();
  19. dispatchSessionFinished(e.error, completeMsg, null);
  20. }
  21. return true;
  22. }
  23. }
  24. };

之后执行了commitLocked函数:

  1. private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
  2. throws PackageManagerException {
  3. ……
  4. try {
  5. resolveStageDir();
  6. } catch (IOException e) {
  7. throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
  8. "Failed to resolve stage location", e);
  9. }
  10. // 验证app是否正常
  11. validateInstallLocked(pkgInfo, appInfo);
  12. Preconditions.checkNotNull(mPackageName);
  13. Preconditions.checkNotNull(mSignatures);
  14. Preconditions.checkNotNull(mResolvedBaseFile);
  15. if (!mPermissionsAccepted) {
  16. // 安装权限获得
  17. final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
  18. intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
  19. intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
  20. try {
  21. mRemoteObserver.onUserActionRequired(intent);
  22. } catch (RemoteException ignored) {
  23. }
  24. close();
  25. return;
  26. }
  27. ……
  28. if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
  29. try {
  30. final List<File> fromFiles = mResolvedInheritedFiles;
  31. final File toDir = resolveStageDir();
  32. if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
  33. if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
  34. throw new IllegalStateException("mInheritedFilesBase == null");
  35. }
  36. if (isLinkPossible(fromFiles, toDir)) {
  37. if (!mResolvedInstructionSets.isEmpty()) {
  38. final File oatDir = new File(toDir, "oat");
  39. // 创建oat文件夹
  40. createOatDirs(mResolvedInstructionSets, oatDir);
  41. }
  42. linkFiles(fromFiles, toDir, mInheritedFilesBase);
  43. } else {
  44. copyFiles(fromFiles, toDir);
  45. }
  46. } catch (IOException e) {
  47. throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
  48. "Failed to inherit existing install", e);
  49. }
  50. }
  51. mInternalProgress = 0.5f;
  52. computeProgressLocked(true);
  53. // 解压native动态库
  54. extractNativeLibraries(mResolvedStageDir, params.abiOverride);、
  55. ……
  56. final UserHandle user;
  57. if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
  58. user = UserHandle.ALL;
  59. } else {
  60. user = new UserHandle(userId);
  61. }
  62. mRelinquished = true;
  63. // 开始真正的安装
  64. mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
  65. installerPackageName, installerUid, user, mCertificates);
  66. }

最后执行了PackageManagerService.java的installStage函数:

  1. void installStage(String packageName, File stagedDir, String stagedCid,
  2. IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
  3. String installerPackageName, int installerUid, UserHandle user,
  4. Certificate[][] certificates) {
  5. ……
  6. final VerificationInfo verificationInfo = new VerificationInfo(
  7. sessionParams.originatingUri, sessionParams.referrerUri,
  8. sessionParams.originatingUid, installerUid);
  9. final OriginInfo origin;
  10. if (stagedDir != null) {
  11. origin = OriginInfo.fromStagedFile(stagedDir);
  12. } else {
  13. origin = OriginInfo.fromStagedContainer(stagedCid);
  14. }
  15. // 发送INIT_COPY信息
  16. final Message msg = mHandler.obtainMessage(INIT_COPY);
  17. final int installReason = fixUpInstallReason(installerPackageName, installerUid,
  18. sessionParams.installReason);
  19. final InstallParams params = new InstallParams(origin, null, observer,
  20. sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
  21. verificationInfo, user, sessionParams.abiOverride,
  22. sessionParams.grantedRuntimePermissions, certificates, installReason);
  23. params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
  24. msg.obj = params;
  25. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
  26. System.identityHashCode(msg.obj));
  27. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
  28. System.identityHashCode(msg.obj));
  29. mHandler.sendMessage(msg);
  30. }

其中发送了INIT_COPY信息:

  1. final ArrayList<HandlerParams> mPendingInstalls =
  2. new ArrayList<HandlerParams>();
  3. case INIT_COPY: {
  4. // 这里取出的其实就是InstallParams
  5. HandlerParams params = (HandlerParams) msg.obj;
  6. //idx为当前等待处理处理的安装请求的个数
  7. int idx = mPendingInstalls.size();
  8. if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
  9. //初始时,mBound的值为false
  10. if (!mBound) {
  11. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
  12. System.identityHashCode(mHandler));
  13. //连接安装服务
  14. if (!connectToService()) {
  15. ……
  16. } else {
  17. //绑定服务成功后,将新的请求加入到mPendingIntalls中,等待处理
  18. mPendingInstalls.add(idx, params);
  19. }
  20. } else {
  21. //如果是第一个请求,则直接发送事件MCS_BOUND,触发处理流程
  22. mPendingInstalls.add(idx, params);
  23. if (idx == 0) {
  24. mHandler.sendEmptyMessage(MCS_BOUND);
  25. }
  26. }
  27. break;
  28. }

INIT_COPY最后会发送MCS_BOUND消息触发接下来的流程:

  1. case MCS_BOUND: {
  2. if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
  3. if (msg.obj != null) {
  4. mContainerService = (IMediaContainerService) msg.obj;
  5. Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
  6. System.identityHashCode(mHandler));
  7. }
  8. if (mContainerService == null) {
  9. ……
  10. } else if (mPendingInstalls.size() > 0) {
  11. HandlerParams params = mPendingInstalls.get(0);
  12. if (params != null) {
  13. ……
  14. if (params.startCopy()) {
  15. if (DEBUG_SD_INSTALL) Log.i(TAG,
  16. "Checking for more work or unbind...");
  17. // 从读了中删除
  18. if (mPendingInstalls.size() > 0) {
  19. mPendingInstalls.remove(0);
  20. }
  21. if (mPendingInstalls.size() == 0) {
  22. ……
  23. } else {
  24. if (DEBUG_SD_INSTALL) Log.i(TAG,
  25. "Posting MCS_BOUND for next work");
  26. mHandler.sendEmptyMessage(MCS_BOUND);
  27. }
  28. }
  29. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  30. }
  31. } else {
  32. Slog.w(TAG, "Empty queue");
  33. }
  34. break;
  35. }

代码中看主要执行了HandlerParams中的startCopy函数,也是在文件PackageManagerService.java中:

  1. final boolean startCopy() {
  2. boolean res;
  3. try {
  4. if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
  5. if (++mRetries > MAX_RETRIES) {
  6. Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
  7. mHandler.sendEmptyMessage(MCS_GIVE_UP);
  8. handleServiceError();
  9. return false;
  10. } else {
  11. handleStartCopy();
  12. res = true;
  13. }
  14. } catch (RemoteException e) {
  15. if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
  16. mHandler.sendEmptyMessage(MCS_RECONNECT);
  17. res = false;
  18. }
  19. handleReturnCode();
  20. return res;
  21. }

继`续执行handleStartCopy函数:

  1. public void handleStartCopy() throws RemoteException {
  2. int ret = PackageManager.INSTALL_SUCCEEDED;
  3. // 决定是安装在手机内还是sdcard中,设置对应标志位
  4. if (origin.staged) {
  5. if (origin.file != null) {
  6. installFlags |= PackageManager.INSTALL_INTERNAL;
  7. installFlags &= ~PackageManager.INSTALL_EXTERNAL;
  8. } else if (origin.cid != null) {
  9. installFlags |= PackageManager.INSTALL_EXTERNAL;
  10. installFlags &= ~PackageManager.INSTALL_INTERNAL;
  11. } else {
  12. throw new IllegalStateException("Invalid stage location");
  13. }
  14. }
  15. ……
  16. // 检查APK的安装位置是否正确
  17. if (onInt && onSd) {
  18. // Check if both bits are set.
  19. Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
  20. ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
  21. } else if (onSd && ephemeral) {
  22. Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external");
  23. ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
  24. } else {
  25. pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
  26. packageAbiOverride);
  27. if (DEBUG_EPHEMERAL && ephemeral) {
  28. Slog.v(TAG, "pkgLite for install: " + pkgLite);
  29. }
  30. if (!origin.staged && pkgLite.recommendedInstallLocation
  31. == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
  32. final StorageManager storage = StorageManager.from(mContext);
  33. final long lowThreshold = storage.getStorageLowBytes(
  34. Environment.getDataDirectory());
  35. final long sizeBytes = mContainerService.calculateInstalledSize(
  36. origin.resolvedPath, isForwardLocked(), packageAbiOverride);
  37. try {
  38. mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
  39. pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
  40. installFlags, packageAbiOverride);
  41. } catch (InstallerException e) {
  42. Slog.w(TAG, "Failed to free cache", e);
  43. }
  44. if (pkgLite.recommendedInstallLocation
  45. == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
  46. pkgLite.recommendedInstallLocation
  47. = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
  48. }
  49. }
  50. }
  51. ……
  52. // createInstallArgs用于创建一个安装参数对象
  53. final InstallArgs args = createInstallArgs(this);
  54. mArgs = args;
  55. ……
  56. // 调用InstallArgs的copyApk函数
  57. ret = args.copyApk(mContainerService, true);
  58. ……
  59. mRet = ret;
  60. }

handleStartCopy主要功能是获取安装位置信息以及复制apk到指定位置。

InstallArgs中的copyApk负责复制APK文件,具体实现在子类FileInstallArgs和MoveInstallArgs里面:

  1. private InstallArgs createInstallArgs(InstallParams params) {
  2. if (params.move != null) {
  3. return new MoveInstallArgs(params);
  4. } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
  5. return new AsecInstallArgs(params);
  6. } else {
  7. return new FileInstallArgs(params);
  8. }
  9. }

继续看下startCopy中的handleReturnCode函数:

  1. void handleReturnCode() {
  2. if (mArgs != null) {
  3. processPendingInstall(mArgs, mRet);
  4. }
  5. }

主要的安装流程都在processPendingInstall函数:

  1. private void processPendingInstall(final InstallArgs args, final int currentStatus) {
  2. mHandler.post(new Runnable() {
  3. public void run() {
  4. mHandler.removeCallbacks(this);
  5. PackageInstalledInfo res = new PackageInstalledInfo();
  6. res.setReturnCode(currentStatus);
  7. res.uid = -1;
  8. res.pkg = null;
  9. res.removedInfo = null;
  10. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
  11. //1、预安装,检查包状态,确保环境ok,如果环境不ok,那么会清理拷贝的文件
  12. args.doPreInstall(res.returnCode);
  13. synchronized (mInstallLock) {
  14. //2、安装,调用installPackageTracedLI进行安装
  15. installPackageTracedLI(args, res);
  16. }
  17. //3、安装收尾
  18. args.doPostInstall(res.returnCode, res.uid);
  19. }
  20. ……
  21. if (!doRestore) {
  22. // No restore possible, or the Backup Manager was mysteriously not
  23. // available -- just fire the post-install work request directly.
  24. if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
  25. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
  26. //4、生成一个POST_INSTALL消息给PackageHanlder
  27. Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
  28. mHandler.sendMessage(msg);
  29. }
  30. }
  31. });
  32. }

看一下installPackageTracedLI函数:

  1. private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
  2. try {
  3. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
  4. installPackageLI(args, res);
  5. } finally {
  6. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  7. }
  8. }

继续跟踪installPackageLI函数:

  1. private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
  2. ……
  3. // PackageParser对象
  4. PackageParser pp = new PackageParser();
  5. pp.setSeparateProcesses(mSeparateProcesses);
  6. pp.setDisplayMetrics(mMetrics);
  7. pp.setCallback(mPackageParserCallback);
  8. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
  9. final PackageParser.Package pkg;
  10. try {
  11. // 开始解析package
  12. pkg = pp.parsePackage(tmpPackageFile, parseFlags);
  13. } catch (PackageParserException e) {
  14. res.setError("Failed parse during installPackageLI", e);
  15. return;
  16. } finally {
  17. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  18. }
  19. if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
  20. Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
  21. res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
  22. "Instant app package must target O");
  23. return;
  24. }
  25. if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
  26. Slog.w(TAG, "Instant app package " + pkg.packageName
  27. + " does not target targetSandboxVersion 2");
  28. res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
  29. "Instant app package must use targetSanboxVersion 2");
  30. return;
  31. }
  32. if (pkg.applicationInfo.isStaticSharedLibrary()) {
  33. // 静态库
  34. renameStaticSharedLibraryPackage(pkg);
  35. // No static shared libs on external storage
  36. if (onExternal) {
  37. Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
  38. res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
  39. "Packages declaring static-shared libs cannot be updated");
  40. return;
  41. }
  42. }
  43. try {
  44. //2. 加载证书,获取签名信息
  45. if (args.certificates != null) {
  46. try {
  47. PackageParser.populateCertificates(pkg, args.certificates);
  48. } catch (PackageParserException e) {
  49. PackageParser.collectCertificates(pkg, parseFlags);
  50. }
  51. } else {
  52. PackageParser.collectCertificates(pkg, parseFlags);
  53. }
  54. } catch (PackageParserException e) {
  55. res.setError("Failed collect during installPackageLI", e);
  56. return;
  57. }
  58. pp = null;
  59. String oldCodePath = null;
  60. boolean systemApp = false;
  61. synchronized (mPackages) {
  62. // 3.检测packages是否已经存在
  63. if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
  64. String oldName = mSettings.getRenamedPackageLPr(pkgName);
  65. if (pkg.mOriginalPackages != null
  66. && pkg.mOriginalPackages.contains(oldName)
  67. && mPackages.containsKey(oldName)) {
  68. pkg.setPackageName(oldName);
  69. pkgName = pkg.packageName;
  70. replace = true;
  71. if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
  72. + oldName + " pkgName=" + pkgName);
  73. } else if (mPackages.containsKey(pkgName)) {
  74. replace = true;
  75. if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
  76. }
  77. ……
  78. if (replace) {
  79. // 4.更新已经存在的packages
  80. PackageParser.Package oldPackage = mPackages.get(pkgName);
  81. final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
  82. final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
  83. if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
  84. && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
  85. res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
  86. "Package " + pkg.packageName + " new target SDK " + newTargetSdk
  87. + " doesn't support runtime permissions but the old"
  88. + " target SDK " + oldTargetSdk + " does.");
  89. return;
  90. }
  91. final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
  92. final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
  93. if (oldTargetSandbox == 2 && newTargetSandbox != 2) {
  94. res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
  95. "Package " + pkg.packageName + " new target sandbox "
  96. + newTargetSandbox + " is incompatible with the previous value of"
  97. + oldTargetSandbox + ".");
  98. return;
  99. }
  100. if (oldPackage.parentPackage != null) {
  101. res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
  102. "Package " + pkg.packageName + " is child of package "
  103. + oldPackage.parentPackage + ". Child packages "
  104. + "can be updated only through the parent package.");
  105. return;
  106. }
  107. }
  108. }
  109. ……
  110. startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
  111. try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
  112. "installPackageLI")) {
  113. if (replace) {
  114. if (pkg.applicationInfo.isStaticSharedLibrary()) {
  115. // 4.更新已经存在的packages
  116. PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
  117. if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
  118. res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
  119. + "static-shared libs cannot be updated");
  120. return;
  121. }
  122. }
  123. replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
  124. installerPackageName, res, args.installReason);
  125. } else {
  126. // 5.安装新的packages
  127. installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
  128. args.user, installerPackageName, volumeUuid, res, args.installReason);
  129. }
  130. }
  131. ……
  132. }

这一段代码比较多,主要解析APK的AndroidManifest.xml,将每个标签对应的信息添加到Package的相关列表中,如将下的信息添加到Package的activities列表等。

  1. 加载apk证书,获取签名信息
  2. 检查目前安装的APK是否在系统中已存在:
    已存在,则调用replacePackageLIF进行替换安装。
    不存在,否则调用installNewPackageLIF进行安装。

继续看一下installNewPackageLIF函数:

  1. private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
  2. int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
  3. PackageInstalledInfo res, int installReason) {
  4. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
  5. String pkgName = pkg.packageName;
  6. if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
  7. synchronized(mPackages) {
  8. final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
  9. if (renamedPackage != null) {
  10. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
  11. + " without first uninstalling package running as "
  12. + renamedPackage);
  13. return;
  14. }
  15. if (mPackages.containsKey(pkgName)) {
  16. // Don't allow installation over an existing package with the same name.
  17. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
  18. + " without first uninstalling.");
  19. return;
  20. }
  21. }
  22. try {
  23. // 1. 安装apk
  24. PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
  25. System.currentTimeMillis(), user);
  26. // 更新set
  27. updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
  28. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
  29. prepareAppDataAfterInstallLIF(newPackage);
  30. } else {
  31. // Remove package from internal structures, but keep around any
  32. // data that might have already existed
  33. deletePackageLIF(pkgName, UserHandle.ALL, false, null,
  34. PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
  35. }
  36. } catch (PackageManagerException e) {
  37. res.setError("Package couldn't be installed in " + pkg.codePath, e);
  38. }
  39. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  40. }

scanPackageTracedL函数最后会安装apk:

  1. private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
  2. int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
  3. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
  4. try {
  5. return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
  6. } finally {
  7. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  8. }
  9. }

继续执行scanPackageLI:

  1. private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
  2. int scanFlags, long currentTime, @Nullable UserHandle user)
  3. throws PackageManagerException {
  4. boolean success = false;
  5. try {
  6. final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
  7. currentTime, user);
  8. success = true;
  9. return res;
  10. } finally {
  11. if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
  12. // DELETE_DATA_ON_FAILURES is only used by frozen paths
  13. destroyAppDataLIF(pkg, UserHandle.USER_ALL,
  14. StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
  15. destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
  16. }
  17. }
  18. }

scanPackageDirtyLI是apk安装的核心部分,下一篇文章继续介绍下。

到这里基本上安装就结束了。接下来看下流程图:

22.png
image.png
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/679927
推荐阅读
相关标签
  

闽ICP备14008679号