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类访问
lib native库文件
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函数:

int adb_commandline(int argc, const char** argv) {……else if (!strcmp(argv[0], "install")) {if (argc < 2) return usage("install requires an argument");if (_use_legacy_install()) {return install_app_legacy(transport_type, serial, argc, argv);}return install_app(transport_type, serial, argc, argv);}……return 1;
}

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

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";static const char *const SD_DEST = "/sdcard/tmp/%s";const char* where = DATA_DEST;……int result = -1;std::vector<const char*> apk_file = {argv[last_apk]};std::string apk_dest = android::base::StringPrintf(where, android::base::Basename(argv[last_apk]).c_str());// 复制app到/data/local/tmp/下if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;argv[last_apk] = apk_dest.c_str(); //执行pm命令result = pm_command(transport, serial, argc, argv);cleanup_apk:delete_file(transport, serial, apk_dest);return result;
}

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

Pm.java中的runInstall函数:

private int runInstall() throws RemoteException {long startedTime = SystemClock.elapsedRealtime();final InstallParams params = makeInstallParams();final String inPath = nextArg();if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {File file = new File(inPath);if (file.isFile()) {try {// 使用PackageParser解析apk包ApkLite baseApk = PackageParser.parseApkLite(file, 0);PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,null, null);params.sessionParams.setSize(PackageHelper.calculateInstalledSize(pkgLite, false,params.sessionParams.abiOverride));} catch (PackageParserException | IOException e) {System.err.println("Error: Failed to parse APK file: " + e);return 1;}} else {System.err.println("Error: Can't open non-file: " + inPath);return 1;}}// 创建Sessionfinal int sessionId = doCreateSession(params.sessionParams,params.installerPackageName, params.userId);try {if (inPath == null && params.sessionParams.sizeBytes == -1) {System.err.println("Error: must either specify a package size or an APK file");return 1;}// 写入Sessionif (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {return 1;}// 提交SessionPair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);if (status.second != PackageInstaller.STATUS_SUCCESS) {return 1;}Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()- startedTime) + " ms");System.out.println("Success");return 0;} finally {try {mInstaller.abandonSession(sessionId);} catch (Exception ignore) {}}}

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

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

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

private int doCreateSession(SessionParams params, String installerPackageName, int userId)throws RemoteException {userId = translateUserId(userId, "runInstallCreate");if (userId == UserHandle.USER_ALL) {userId = UserHandle.USER_SYSTEM;params.installFlags |= PackageManager.INSTALL_ALL_USERS;}final int sessionId = mInstaller.createSession(params, installerPackageName, userId);return sessionId;}mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));mInstaller = mPm.getPackageInstaller();

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

public IPackageInstaller getPackageInstaller() {if (getInstantAppPackageName(Binder.getCallingUid()) != null) {return null;}return mInstallerService;}final PackageInstallerService mInstallerService;mInstallerService = new PackageInstallerService(context, this);

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

public int createSession(SessionParams params, String installerPackageName, int userId) {try {return createSessionInternal(params, installerPackageName, userId);} catch (IOException e) {throw ExceptionUtils.wrap(e);}}private int createSessionInternal(SessionParams params, String installerPackageName, int userId)throws IOException {// 权限检查final int callingUid = Binder.getCallingUid();mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {throw new SecurityException("User restriction prevents installing");}……// 获取图标数据if (params.appIcon != null) {final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);final int iconSize = am.getLauncherLargeIconSize();if ((params.appIcon.getWidth() > iconSize * 2)|| (params.appIcon.getHeight() > iconSize * 2)) {params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,true);}}……final long createdMillis = System.currentTimeMillis();//创建文件夹File stageDir = null;String stageCid = null;if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {final boolean isInstant =(params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);} else {stageCid = buildExternalStageCid(sessionId);}// 创建sessionsession = new PackageInstallerSession(mInternalCallback, mContext, mPm,mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,params, createdMillis, stageDir, stageCid, false, false);synchronized (mSessions) {mSessions.put(sessionId, session);}mCallbacks.notifySessionCreated(session.sessionId, session.userId);writeSessionsAsync();return sessionId;}

之后开始进入doWriteSession函数:

private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,boolean logSuccess) throws RemoteException {if (STDIN_PATH.equals(inPath)) {inPath = null;} else if (inPath != null) {final File file = new File(inPath);if (file.isFile()) {sizeBytes = file.length();}}final SessionInfo info = mInstaller.getSessionInfo(sessionId);PackageInstaller.Session session = null;InputStream in = null;OutputStream out = null;try {session = new PackageInstaller.Session(mInstaller.openSession(sessionId));if (inPath != null) {in = new FileInputStream(inPath);} else {in = new SizedInputStream(System.in, sizeBytes);}out = session.openWrite(splitName, 0, sizeBytes);int total = 0;byte[] buffer = new byte[65536];int c;while ((c = in.read(buffer)) != -1) {total += c;out.write(buffer, 0, c);if (info.sizeBytes > 0) {final float fraction = ((float) c / (float) info.sizeBytes);session.addProgress(fraction);}}session.fsync(out);if (logSuccess) {System.out.println("Success: streamed " + total + " bytes");}return PackageInstaller.STATUS_SUCCESS;} catch (IOException e) {System.err.println("Error: failed to write; " + e.getMessage());return PackageInstaller.STATUS_FAILURE;} finally {IoUtils.closeQuietly(out);IoUtils.closeQuietly(in);IoUtils.closeQuietly(session);}}

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

最后开始执行doCommitSession函数:

private Pair<String, Integer> doCommitSession(int sessionId, boolean logSuccess)throws RemoteException {PackageInstaller.Session session = null;try {// 获取sessionsession = new PackageInstaller.Session(mInstaller.openSession(sessionId));final LocalIntentReceiver receiver = new LocalIntentReceiver();// 执行session的commit函数session.commit(receiver.getIntentSender());final Intent result = receiver.getResult();final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,PackageInstaller.STATUS_FAILURE);if (status == PackageInstaller.STATUS_SUCCESS) {if (logSuccess) {System.out.println("Success");}} else {System.err.println("Failure ["+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");}return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status);} finally {IoUtils.closeQuietly(session);}}

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

public static class Session implements Closeable {private IPackageInstallerSession mSession;public void commit(@NonNull IntentSender statusReceiver) {try {mSession.commit(statusReceiver);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}}

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

public void commit(IntentSender statusReceiver) {Preconditions.checkNotNull(statusReceiver);final boolean wasSealed;synchronized (mLock) {wasSealed = mSealed;if (!mSealed) {for (RevocableFileDescriptor fd : mFds) {if (!fd.isRevoked()) {throw new SecurityException("Files still open");}}for (FileBridge bridge : mBridges) {if (!bridge.isClosed()) {throw new SecurityException("Files still open");}}mSealed = true;}mClientProgress = 1f;computeProgressLocked(true);}if (!wasSealed) {mCallback.onSessionSealedBlocking(this);}mActiveCount.incrementAndGet();final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();}

函数中发送消息MSG_COMMIT:

private final Handler.Callback mHandlerCallback = new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {final PackageInfo pkgInfo = mPm.getPackageInfo(params.appPackageName, PackageManager.GET_SIGNATURES| PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);final ApplicationInfo appInfo = mPm.getApplicationInfo(params.appPackageName, 0, userId);synchronized (mLock) {if (msg.obj != null) {mRemoteObserver = (IPackageInstallObserver2) msg.obj;}try {commitLocked(pkgInfo, appInfo);} catch (PackageManagerException e) {final String completeMsg = ExceptionUtils.getCompleteMessage(e);Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);destroyInternal();dispatchSessionFinished(e.error, completeMsg, null);}return true;}}};

之后执行了commitLocked函数:

private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)throws PackageManagerException {……try {resolveStageDir();} catch (IOException e) {throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,"Failed to resolve stage location", e);}// 验证app是否正常validateInstallLocked(pkgInfo, appInfo);Preconditions.checkNotNull(mPackageName);Preconditions.checkNotNull(mSignatures);Preconditions.checkNotNull(mResolvedBaseFile);if (!mPermissionsAccepted) {// 安装权限获得final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);try {mRemoteObserver.onUserActionRequired(intent);} catch (RemoteException ignored) {}close();return;}……if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {try {final List<File> fromFiles = mResolvedInheritedFiles;final File toDir = resolveStageDir();if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {throw new IllegalStateException("mInheritedFilesBase == null");}if (isLinkPossible(fromFiles, toDir)) {if (!mResolvedInstructionSets.isEmpty()) {final File oatDir = new File(toDir, "oat");// 创建oat文件夹createOatDirs(mResolvedInstructionSets, oatDir);}linkFiles(fromFiles, toDir, mInheritedFilesBase);} else {copyFiles(fromFiles, toDir);}} catch (IOException e) {throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,"Failed to inherit existing install", e);}}mInternalProgress = 0.5f;computeProgressLocked(true);// 解压native动态库extractNativeLibraries(mResolvedStageDir, params.abiOverride);、……final UserHandle user;if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {user = UserHandle.ALL;} else {user = new UserHandle(userId);}mRelinquished = true;// 开始真正的安装mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,installerPackageName, installerUid, user, mCertificates);}

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

void installStage(String packageName, File stagedDir, String stagedCid,IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,String installerPackageName, int installerUid, UserHandle user,Certificate[][] certificates) {……final VerificationInfo verificationInfo = new VerificationInfo(sessionParams.originatingUri, sessionParams.referrerUri,sessionParams.originatingUid, installerUid);final OriginInfo origin;if (stagedDir != null) {origin = OriginInfo.fromStagedFile(stagedDir);} else {origin = OriginInfo.fromStagedContainer(stagedCid);}// 发送INIT_COPY信息final Message msg = mHandler.obtainMessage(INIT_COPY);final int installReason = fixUpInstallReason(installerPackageName, installerUid,sessionParams.installReason);final InstallParams params = new InstallParams(origin, null, observer,sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,verificationInfo, user, sessionParams.abiOverride,sessionParams.grantedRuntimePermissions, certificates, installReason);params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));msg.obj = params;Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",System.identityHashCode(msg.obj));Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(msg.obj));mHandler.sendMessage(msg);}

其中发送了INIT_COPY信息:

final ArrayList<HandlerParams> mPendingInstalls =new ArrayList<HandlerParams>();case INIT_COPY: {// 这里取出的其实就是InstallParamsHandlerParams params = (HandlerParams) msg.obj;//idx为当前等待处理处理的安装请求的个数int idx = mPendingInstalls.size();if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);//初始时,mBound的值为falseif (!mBound) {Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",System.identityHashCode(mHandler));//连接安装服务if (!connectToService()) {……} else {//绑定服务成功后,将新的请求加入到mPendingIntalls中,等待处理mPendingInstalls.add(idx, params);}} else {//如果是第一个请求,则直接发送事件MCS_BOUND,触发处理流程mPendingInstalls.add(idx, params);if (idx == 0) {mHandler.sendEmptyMessage(MCS_BOUND);}}break;}

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

case MCS_BOUND: {if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");if (msg.obj != null) {mContainerService = (IMediaContainerService) msg.obj;Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",System.identityHashCode(mHandler));}if (mContainerService == null) {……} 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) {……} else {if (DEBUG_SD_INSTALL) Log.i(TAG,"Posting MCS_BOUND for next work");mHandler.sendEmptyMessage(MCS_BOUND);}}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}} else {Slog.w(TAG, "Empty queue");}break;}

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

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函数:

public void handleStartCopy() throws RemoteException {int ret = PackageManager.INSTALL_SUCCEEDED;// 决定是安装在手机内还是sdcard中,设置对应标志位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");}}……// 检查APK的安装位置是否正确if (onInt && onSd) {// 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);if (DEBUG_EPHEMERAL && ephemeral) {Slog.v(TAG, "pkgLite for install: " + pkgLite);}if (!origin.staged && pkgLite.recommendedInstallLocation== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {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, 0, 0);pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,installFlags, packageAbiOverride);} catch (InstallerException e) {Slog.w(TAG, "Failed to free cache", e);}if (pkgLite.recommendedInstallLocation== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {pkgLite.recommendedInstallLocation= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;}}}……// createInstallArgs用于创建一个安装参数对象final InstallArgs args = createInstallArgs(this);mArgs = args;……// 调用InstallArgs的copyApk函数ret = args.copyApk(mContainerService, true);……      mRet = ret;}

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

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

private InstallArgs createInstallArgs(InstallParams params) {if (params.move != null) {return new MoveInstallArgs(params);} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {return new AsecInstallArgs(params);} else {return new FileInstallArgs(params);}}

继续看下startCopy中的handleReturnCode函数:

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.setReturnCode(currentStatus);res.uid = -1;res.pkg = null;res.removedInfo = null;if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//1、预安装,检查包状态,确保环境ok,如果环境不ok,那么会清理拷贝的文件args.doPreInstall(res.returnCode);synchronized (mInstallLock) {//2、安装,调用installPackageTracedLI进行安装installPackageTracedLI(args, res);}//3、安装收尾args.doPostInstall(res.returnCode, res.uid);}……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);//4、生成一个POST_INSTALL消息给PackageHanlderMessage msg = mHandler.obtainMessage(POST_INSTALL, token, 0);mHandler.sendMessage(msg);}}});}

看一下installPackageTracedLI函数:

private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");installPackageLI(args, res);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}

继续跟踪installPackageLI函数:

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {……// PackageParser对象PackageParser pp = new PackageParser();pp.setSeparateProcesses(mSeparateProcesses);pp.setDisplayMetrics(mMetrics);pp.setCallback(mPackageParserCallback);Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");final PackageParser.Package pkg;try {// 开始解析packagepkg = pp.parsePackage(tmpPackageFile, parseFlags);} catch (PackageParserException e) {res.setError("Failed parse during installPackageLI", e);return;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,"Instant app package must target O");return;}if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {Slog.w(TAG, "Instant app package " + pkg.packageName+ " does not target targetSandboxVersion 2");res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,"Instant app package must use targetSanboxVersion 2");return;}if (pkg.applicationInfo.isStaticSharedLibrary()) {// 静态库renameStaticSharedLibraryPackage(pkg);// No static shared libs on external storageif (onExternal) {Slog.i(TAG, "Static shared libs can only be installed on internal storage.");res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,"Packages declaring static-shared libs cannot be updated");return;}}try {//2. 加载证书,获取签名信息if (args.certificates != null) {try {PackageParser.populateCertificates(pkg, args.certificates);} catch (PackageParserException e) {PackageParser.collectCertificates(pkg, parseFlags);}} else {PackageParser.collectCertificates(pkg, parseFlags);}} catch (PackageParserException e) {res.setError("Failed collect during installPackageLI", e);return;}pp = null;String oldCodePath = null;boolean systemApp = false;synchronized (mPackages) {// 3.检测packages是否已经存在if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {String oldName = mSettings.getRenamedPackageLPr(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 (replace) {// 4.更新已经存在的packagesPackageParser.Package oldPackage = mPackages.get(pkgName);final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1&& newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,"Package " + pkg.packageName + " new target SDK " + newTargetSdk+ " doesn't support runtime permissions but the old"+ " target SDK " + oldTargetSdk + " does.");return;}final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;if (oldTargetSandbox == 2 && newTargetSandbox != 2) {res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,"Package " + pkg.packageName + " new target sandbox "+ newTargetSandbox + " is incompatible with the previous value of"+ oldTargetSandbox + ".");return;}if (oldPackage.parentPackage != null) {res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,"Package " + pkg.packageName + " is child of package "+ oldPackage.parentPackage + ". Child packages "+ "can be updated only through the parent package.");return;}}}……startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,"installPackageLI")) {if (replace) {if (pkg.applicationInfo.isStaticSharedLibrary()) {// 4.更新已经存在的packagesPackageParser.Package existingPkg = mPackages.get(pkg.packageName);if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "+ "static-shared libs cannot be updated");return;}}replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,installerPackageName, res, args.installReason);} else {// 5.安装新的packagesinstallNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,args.user, installerPackageName, volumeUuid, res, args.installReason);}}……}

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

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

继续看一下installNewPackageLIF函数:

private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,PackageInstalledInfo res, int installReason) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");String pkgName = pkg.packageName;if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);synchronized(mPackages) {final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);if (renamedPackage != null) {res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling package running as "+ renamedPackage);return;}if (mPackages.containsKey(pkgName)) {// Don't allow installation over an existing package with the same name.res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling.");return;}}try {// 1. 安装apkPackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,System.currentTimeMillis(), user);// 更新setupdateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {prepareAppDataAfterInstallLIF(newPackage);} else {// Remove package from internal structures, but keep around any// data that might have already existeddeletePackageLIF(pkgName, UserHandle.ALL, false, null,PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);}} catch (PackageManagerException e) {res.setError("Package couldn't be installed in " + pkg.codePath, e);}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}

scanPackageTracedL函数最后会安装apk:

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

继续执行scanPackageLI:

private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,int scanFlags, long currentTime, @Nullable UserHandle user)throws PackageManagerException {boolean success = false;try {final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,currentTime, user);success = true;return res;} finally {if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {// DELETE_DATA_ON_FAILURES is only used by frozen pathsdestroyAppDataLIF(pkg, UserHandle.USER_ALL,StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);}}}

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

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

22.png

image.png


http://www.taodudu.cc/news/show-2659183.html

相关文章:

  • adb Error: failed to write; /data/local/tmp/??.apk (No such file or directory)
  • Codewar刷题总结
  • 刷题时遇到的经典解法(实时更新)
  • 转换句子的首字母为大小写(Jaden Casing Strings)
  • Jaden Casing Strings
  • 7kyu Jaden Casing Strings
  • Codewars-Java编程刷题学习4-Jaden Casing Strings
  • Jaden的推特
  • NR PHR流程
  • SQL语句 操作实例
  • 最优化理论——罚函数法·乘子法
  • ZigBee之帧结构
  • 利用 MATLAB 编程实现乘子法求解约束最优化问题。
  • 5G NR 上行调度算法流程
  • 【课程作业】学术英语写作:文献阅读报告2
  • CCR, CCD, CDA, EMR, PHR
  • UWB基本原理分析2
  • 【转载】MiniGUI输入法词库更新
  • UWB基本原理分析
  • 【Algorithm】一般约束优化问题——PHR算法及其Matlab实现
  • 深圳现货原装正品JST提供各种专为汽车市场而设的线束连接器PAP-12V-S PAP-13V-S PAP-10V-S PHR-9 PHR-10
  • 【智慧医疗】EMR vs EHR vs PHR 有何区别?
  • LTE:PHR Power Headroom Report 功率余量上报
  • 在php中phr是什么意思,phr. 相当多的_____
  • 在php中phr是什么意思,虽败犹荣 AGO.phr:WESG让我们如获新生
  • LTE资源调度(6)-功率余量报告PHR
  • 上行PHR余量提升优化思路
  • 基于深度学习股票预测系统
  • 股票预测项目
  • LSTM预测多支股票的收盘价

Androidapk安装流程之adb安装相关推荐

  1. WSA微软官方安装教程(ADB安装教程)

    WSA其实是Windows Subsystem for Android(适用于Windows的Android™️子系统)的缩写,让你可以在Win11上运行安卓软件.当然,也不止是Amazon应用商店里 ...

  2. 安装教程之PyCharm安装

    1.安装网址 官网:https://www.jetbrains.com/pycharm/download/other.html 个人网盘:链接:https://pan.baidu.com/s/1Yb8 ...

  3. iOS Sprite Kit教程之xcode安装以及苹果帐号绑定

    iOS Sprite Kit教程之xcode安装以及苹果帐号绑定 其它的网站上下载安装Xcode 有时候,应用商店下载较慢,所以用户也可以选择从其他网站下载Xcode安装文件.下面讲解这种Xcode的 ...

  4. anaconda的python使用教程-Python安装教程之Anaconda入门使用总结

    原标题:Python安装教程之Anaconda入门使用总结 如今参加Python培训学习Python开发的小伙伴对Python安装教程比较感兴趣,本篇文章小编就和读者们分享一下Python安装教程之A ...

  5. android adb 静默安装,Android_如何静默安装

    Android常用代码之普通及系统权限静默安装APK 本文主要介绍程序如何安装apk,包括普通模式安装和系统权限静默安装. 如果是非系统应用请直接查看:Android常用代码之APK root权限静默 ...

  6. 在安卓模拟器中,adb安装apk常见错误

     转自应用汇ADB安装错误常见列表:http://www.appchina.com/mini/help/error_descrition.html 应用汇常见错误列表 应用汇的安装功能是基于安卓系 ...

  7. adb安装报错情形以及解决办法

    1.  手机系统内存剩余空间不足,导致安装失败: 提示情形:  a. 提示为"ADB_INSTALL_FAILED_INSUFFICIENT_STORAGE",意为手机存储空间不足 ...

  8. adb安装应用失败,错误码整理

    内容来自作者:帝龙至尊 链接:https://www.jianshu.com/p/65065b32bb50 来源:简书 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. adb p ...

  9. 禁止应用和adb安装APK

    Platform: RK3368 OS: Android 6.0 Kernel: 3.10.0 禁止应用和adb安装非平签名的APK,使用adb安装返回"Failure [INSTALL_F ...

  10. 小米手机通过adb安装应用异常处理

    小米手机通过adb安装应用异常处理 1.报错:Failure [INSTALL_FAILED_USER_RESTRICTED: Install canceled by user] 处理办法: 关闭mi ...

最新文章

  1. 口腔微生物——“你的大能量,超乎我想象”
  2. 【Android 逆向】substrate 框架 ( substrate 简介 | substrate 相关文档资料 )
  3. VLC播放器web插件接口(Part2)
  4. 游戏CFHD,狙可不是随便就起的,狙击的作用是辅助
  5. AttributeError: 'numpy.ndarray' object has no attribute 'value_counts'
  6. [DP/单调队列]BZOJ 2059 [Usaco2010 Nov]Buying Feed 购买饲料
  7. iOS开发UI篇—使用嵌套模型完成的一个简单汽车图标展示程序
  8. SELinux系列(九)——SELinux auditd日志系统的安装与启动
  9. 剑指offer面试题09. 用两个栈实现队列(队列、栈)
  10. MySQL常用的日期时间函数
  11. 有趣的github项目
  12. 修改计算机系统参数软件,机器码修改专家(修改电脑机器码工具) v2.0官方版
  13. AI发票扫描识别sdk软件接口
  14. 计算机组老师颁奖词,学校优秀老师颁奖词
  15. 关于SQL2005安装后更改计算机名后…
  16. eclipse安装GWT插件
  17. 【华为OJ】【MML命令执行结果查询】
  18. 报告:加密货币和石油市场暴跌是市场接近“闪电崩盘”的标志
  19. c语言求最小公倍数和最大公约数
  20. 如何使用格式工厂截取音乐或视频的片断

热门文章

  1. mysql启动报错之[ERROR] Found option without preceding group in config file /etc/my.cnf at line
  2. Python爬取下载网易云音乐
  3. 可以使用ActualHeight来判断textblock是否已经trimming
  4. matlab调制变声,MATLAB变声程序代码
  5. 达内python第一次月考题目_第一次月考作文六篇
  6. QClub:Ruby网站架构案例分享──财帮子FreeWheel(10.19 北京)
  7. 游戏项目开发的简单流程
  8. 01.14_学习Java的day23(详解)
  9. Android锁屏勒索病毒分析(4)秒抢红包
  10. c#数字验证码功能,以及判断用户输入是否正确。