android adb install apk的安装流程
一、简介1.Android上应用安装可以分为以下几种方式:通过adb命令安装:adb 命令包括adb push/install用户下载的Apk,通过系统安装器packageinstaller安装该Apk。packageinstaller是系统内置的应用程序,用于安装和卸载应用程序。系统开机时安装系统应用。电脑或者手机上的应用商店自动安装第三种系统安装我们在上个章节P...
目录:
一、PackageManagerService启动流程
二、apk adb安装流程
一、简介
1.Android上应用安装可以分为以下几种方式:
- 通过adb命令安装:adb 命令包括adb push/install
- 用户下载的Apk,通过系统安装器packageinstaller安装该Apk。packageinstaller是系统内置的应用程序,用于安装和卸载应用程序。
- 系统开机时安装系统应用。
- 电脑或者手机上的应用商店自动安装
第三种系统安装我们在上个章节PackageManagerService启动流程已经说过,剩余的三种其实没什么太大的区别,主要的流程都是:1)PackageInstallerService.createSession创建sessionId。
2) session = new PackageInstaller.Session( mInterface.getPackageInstaller().openSession(sessionId)),splitName=base.apk
out = session.openWrite(splitName, 0, sizeBytes);创建一个临时的apk :/data/app/vmd+sessionId+tmp/base.apk ,把原apkt保存到刚刚创建的apk文件中
3) PackageInstaller.Session.commit
他们的差别是:第一种是通过adb的方式安装,第二中是通过packageinstaller.apk的方式安装,第三种是oem厂商自己写,可以满足静默安装,默认赋予动态权限等。
2.APK文件结构:
目录/文件 | 描述 |
---|---|
assert | 存放的原生资源文件,通过AssetManager类访问。 |
lib | 存放库文件。 |
META-INF | 保存应用的签名信息,签名信息可以验证APK文件的完整性。 |
res | 存放资源文件。res中除了raw子目录,其他的子目录都参与编译,这些子目录下的资源是通过编译出的R类在代码中访问。 |
AndroidManifest.xml | 用来声明应用程序的包名称、版本、组件和权限等数据。 apk中的AndroidManifest.xml经过压缩,可以通过AXMLPrinter2工具解开。 |
classes.dex | Java源码编译后生成的Java字节码文件。 |
resources.arsc | 编译后的二进制资源文件。 |
apk的安装主要会解析上面哪几个文件呢?assert,lib,META-INF,res,AndroidManifest.xml。至于classes.dex是在apk启动的时候加载的。
3.adb install 安装时序图
上面图片不清晰的,可以查看https://download.csdn.net/download/Bill_xiao/12328139
二、adb 安装流程
1.adb install +apk,这个命令会通过adb程序调用shell脚本,shell脚本会根据传递的参数来选择调用cmd程序,cmd在system/bin下面。
cmd.cpp的main函数会执行 status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args, cb, result);而它会调用PackageManagerServcie.onShellCommand方法
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
(new PackageManagerShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
PackageManagerShellCommand 继承ShellCommand ShellCommand.exec方法如下,可以看出会回调子类的onCommand方法
public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
String cmd;
int start;
if (args != null && args.length > 0) {
cmd = args[0];
start = 1;
} else {
cmd = null;
start = 0;
}
init(target, in, out, err, args, callback, start);
// Log.i(" PackageManagerService-xiao", "ShellCommand exec cmd:"+cmd);
mCmd = cmd;
mResultReceiver = resultReceiver;
if (DEBUG) Log.i(TAG, "Starting command " + mCmd + " on " + mTarget);
int res = -1;
try {
res = onCommand(mCmd);
if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
} catch (SecurityException e) {
PrintWriter eout = getErrPrintWriter();
eout.println("Security exception: " + e.getMessage());
eout.println();
e.printStackTrace(eout);
} catch (Throwable e) {
// Unlike usual calls, in this case if an exception gets thrown
// back to us we want to print it back in to the dump data, since
// that is where the caller expects all interesting information to
// go.
PrintWriter eout = getErrPrintWriter();
eout.println();
eout.println("Exception occurred while executing:");
e.printStackTrace(eout);
} finally {
if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
if (mOutPrintWriter != null) {
mOutPrintWriter.flush();
}
if (mErrPrintWriter != null) {
mErrPrintWriter.flush();
}
if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
mResultReceiver.send(res, null);
}
if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
return res;
}
@Override
public int onCommand(String cmd) {
if (cmd == null) {
return handleDefaultCommands(cmd);
}
final PrintWriter pw = getOutPrintWriter();
try {
switch(cmd) {
case "install":
return runInstall();
case "install-abandon":
case "install-destroy":
return runInstallAbandon();
case "install-commit":
return runInstallCommit();
case "install-create":
return runInstallCreate();
case "install-remove":
return runInstallRemove();
case "install-write":
return runInstallWrite();
case "install-existing":
return runInstallExisting();
case "compile":
return runCompile();
case "reconcile-secondary-dex-files":
return runreconcileSecondaryDexFiles();
case "bg-dexopt-job":
return runDexoptJob();
case "dump-profiles":
return runDumpProfiles();
case "list":
return runList();
case "uninstall":
return runUninstall();
case "resolve-activity":
return runResolveActivity();
case "query-activities":
return runQueryIntentActivities();
case "query-services":
return runQueryIntentServices();
case "query-receivers":
return runQueryIntentReceivers();
case "suspend":
return runSuspend(true);
case "unsuspend":
return runSuspend(false);
case "set-home-activity":
return runSetHomeActivity();
case "get-privapp-permissions":
return runGetPrivappPermissions();
case "get-privapp-deny-permissions":
return runGetPrivappDenyPermissions();
case "get-instantapp-resolver":
return runGetInstantAppResolver();
case "has-feature":
return runHasFeature();
default:
return handleDefaultCommands(cmd);
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
}
return -1;
}
从上面函数就能看出,不同的参数会执行不同的方法,我们的install,所以会执行runInstall()方法:
1.doCreateSession :创建PackageInstaller.Session函数。
2.doWriteSplit :创建一个临时的apk :/data/app/vmd+sessionId+tmp/base.apk
3.doCommitSession :执行PackageInstaller.Session.commit方法,这一步才开始apk的安装。等待系统安装完成会发送一个广播带有PackageInstaller.EXTRA_STATUS字段的信息,里面回保存安装结果success或者Failure的原因
private int runInstall() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final InstallParams params = makeInstallParams();
final String inPath = getNextArg();
setParamsSize(params, inPath);
//创建sessionId mSessions.put(sessionId, session);
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
boolean abandonSession = true;
try {
if (inPath == null && params.sessionParams.sizeBytes == -1) {
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
//创建一个临时的apk :/data/app/vmd+sessionId+tmp/base.apk ,把原apk保存到刚刚创建的apk文件中
if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
if (doCommitSession(sessionId, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
abandonSession = false;
pw.println("Success");
return 0;
} finally {
if (abandonSession) {
try {
doAbandonSession(sessionId, false /*logSuccess*/);
} catch (Exception ignore) {
}
}
}
}
我们来看看sessionId到底是什么?
如下代码可以得出:
1.会检查用户是否具有安装apk的权限,添加一些安装flag
2.随机产生一个sessionId值,创建stageDir目录:/data/app/vmd+sessionId+tmp
3.创建一个新的session,并且 保存值到mSessions,mSessions.put(sessionId, session);
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");//检查APK安装权限
//检查用户权限
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
throw new SecurityException("User restriction prevents installing");
}
//如果是root权限或者shell脚本安装(adb 安装)的赋值INSTALL_FROM_ADB
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
params.installFlags |= PackageManager.INSTALL_FROM_ADB;
} else {
mAppOps.checkPackage(callingUid, installerPackageName);//检查包名跟uid是否匹配
params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
&& !mPm.isCallerVerifier(callingUid)) {
params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
}
}
// Only system components can circumvent runtime permissions when installing.
//检查运行权限 adb安装就没有这个检查
if ((params.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");
}
//检查是否安装到外部存储,新版本不允许。
if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
|| (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
throw new IllegalArgumentException(
"New installs into ASEC containers no longer supported");
}
// Defensively resize giant app icons
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);
}
}
switch (params.mode) {
case SessionParams.MODE_FULL_INSTALL:
case SessionParams.MODE_INHERIT_EXISTING:
break;
default:
throw new IllegalArgumentException("Invalid install mode: " + params.mode);
}
// If caller requested explicit location, sanity check it, otherwise
// resolve the best internal or adopted location.
//检测apk需要安装到指定文件夹挂载情况,/data/app
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
if (!PackageHelper.fitsOnInternal(mContext, params)) {
throw new IOException("No suitable internal storage available");
}
} else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
if (!PackageHelper.fitsOnExternal(mContext, params)) {
throw new IOException("No suitable external storage available");
}
} else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
// For now, installs to adopted media are treated as internal from
// an install flag point-of-view.
params.setInstallFlagsInternal();
} else {
// For now, installs to adopted media are treated as internal from
// an install flag point-of-view.
params.setInstallFlagsInternal();
// Resolve best location for install, based on combination of
// requested install flags, delta size, and manifest settings.
final long ident = Binder.clearCallingIdentity();
try {
params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
// Sanity check that installer isn't going crazy
//表示由callingUid进程所执行安装的apk有多少个
final int activeCount = getSessionCount(mSessions, callingUid);
if (activeCount >= MAX_ACTIVE_SESSIONS) {
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
//表示由callingUid进程所已经安装的apk有多少个
final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
throw new IllegalStateException(
"Too many historical sessions for UID " + callingUid);
}
//随机产生一个数字,并且放到mAllocatedSessions
sessionId = allocateSessionIdLocked();
final long createdMillis = System.currentTimeMillis();
// We're staging to exactly one location
File stageDir = null;
String stageCid = null;
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
final boolean isInstant =
(params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
//params.volumeUuid=null stageDir:/data/app/vmd+sessionId+tmp
stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
} else {
stageCid = buildExternalStageCid(sessionId);//"smdl" + sessionId + ".tmp";
}
session = 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);//通知回调session创建成功
writeSessionsAsync();
return sessionId;
}
doWriteSplit比较简单,可以自行研究。那我们来看看doCommitSession 的PackageInstaller.Session.commit做了哪些东西?
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
final boolean wasSealed;
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotDestroyedLocked("commit");
final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
//获取IPackageInstallObserver2.Stub
mRemoteObserver = adapter.getBinder();
if (forTransfer) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
if (mInstallerUid == mOriginalInstallerUid) {
throw new IllegalArgumentException("Session has not been transferred");
}
} else {
//uid检查
if (mInstallerUid != mOriginalInstallerUid) {
throw new IllegalArgumentException("Session has been transferred");
}
}
//没有调用sealAndValidateLocked之前都是false
wasSealed = mSealed;
if (!mSealed) {
try {
sealAndValidateLocked();
} catch (IOException e) {
throw new IllegalArgumentException(e);
} catch (PackageManagerException e) {
destroyInternal();
// Cannot call dispatchFinal synchronous as this might be called from inside the
// system server on the main thread. Hence the call back scheduled in
// dispachFinal has to be scheduled on a different thread.
mHandler.obtainMessage(MSG_SESSION_FINISHED_WITH_EXCEPTION, e).sendToTarget();
return;
}
}
// Client staging is fully done at this point
mClientProgress = 1f;
computeProgressLocked(true);
// This ongoing commit should keep session active, even though client
// will probably close their end.
mActiveCount.incrementAndGet();
mCommitted = true;
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
if (!wasSealed) {
// Persist the fact that we've sealed ourselves to prevent
// mutations of any hard links we create. We do this without holding
// the session lock, since otherwise it's a lock inversion.
mCallback.onSessionSealedBlocking(this);
}
}
主要做了:1.创建PackageInstallObserverAdapter实例,从名字就能知道是用于apk的安装结果观察。
2.调用sealAndValidateLocked()方法
3.发送MSG_COMMIT广播。
先重点查看sealAndValidateLocked做了什么事
private void sealAndValidateLocked() throws PackageManagerException, IOException {
assertNoWriteFileTransfersOpenLocked();
assertPreparedAndNotDestroyedLocked("sealing of session");
//如果此apk已经安装过,或者存在的话,从mPackages中获取packageInfo,如果没有就是null
final PackageInfo pkgInfo = mPm.getPackageInfo(
params.appPackageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
File mFile= resolveStageDirLocked();
mSealed = true;
// Verify that stage looks sane with respect to existing application.
// This currently only ensures packageName, versionCode, and certificate
// consistency.
try {
validateInstallLocked(pkgInfo);
} catch (PackageManagerException e) {
throw e;
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above
throw new PackageManagerException(e);
}
// Read transfers from the original owner stay open, but as the session's data
// cannot be modified anymore, there is no leak of information.
}
从上述的代码看:1.查询此apk是否安装过,如果安装过的话pkgInfo不为空
2.resolveStageDirLocked 获取apk源文件目录,这个目录是在createSession中创建的:/data/app/vmd+sessionId+tmp
3.执行validateInstallLocked方法,扫描/data/app/vmd+sessionId+tmp 目录下的文件,清空缓存文件,对以.apk结尾的文件进行扫描。获取一些基本的apk信息,主要解析mainfest,获取包名及其他属性信息coreApp ,multiArch, use32bitAbi,extractNativeLibs ,versionCode 。
private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
throws PackageManagerException {
mPackageName = null;
mVersionCode = -1;
mSignatures = null;
mResolvedBaseFile = null;
mResolvedStagedFiles.clear();
mResolvedInheritedFiles.clear();
try {
resolveStageDirLocked();
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
"Failed to resolve stage location", e);
}
//移除/data/app/vmd+sessionId+tmp下面.removed结尾的文件
final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
final List<String> removeSplitList = new ArrayList<>();
if (!ArrayUtils.isEmpty(removedFiles)) {
for (File removedFile : removedFiles) {
final String fileName = removedFile.getName();
final String splitName = fileName.substring(
0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
removeSplitList.add(splitName);
}
}
//添加/data/app/vmd+lsessionId+tmp下面,不是.removed结尾的文件
final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
}
// Verify that all staged packages are internally consistent
final ArraySet<String> stagedSplits = new ArraySet<>();
for (File addedFile : addedFiles) {
final ApkLite apk;
try {
int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
flags |= PackageParser.PARSE_IS_EPHEMERAL;
}
//解析apk,主要解析mainfest,获取包名及其他属性信息coreApp ,multiArch, use32bitAbi, extractNativeLibs ,versionCode
apk = PackageParser.parseApkLite(addedFile, flags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
if (!stagedSplits.add(apk.splitName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Split " + apk.splitName + " was defined multiple times");
}
// Use first package to define unknown values
if (mPackageName == null) {
mPackageName = apk.packageName;
mVersionCode = apk.versionCode;
}
if (mSignatures == null) {
mSignatures = apk.signatures;
mCertificates = apk.certificates;
}
assertApkConsistentLocked(String.valueOf(addedFile), apk);
// Take this opportunity to enforce uniform naming
final String targetName;
if (apk.splitName == null) {
targetName = "base.apk";
} else {
targetName = "split_" + apk.splitName + ".apk";
}
if (!FileUtils.isValidExtFilename(targetName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Invalid filename: " + targetName);
}
final File targetFile = new File(mResolvedStageDir, targetName);
if (!addedFile.equals(targetFile)) {
addedFile.renameTo(targetFile);
}
// Base is coming from session
if (apk.splitName == null) {
mResolvedBaseFile = targetFile;
}
mResolvedStagedFiles.add(targetFile);
}
if (removeSplitList.size() > 0) {
if (pkgInfo == null) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Missing existing base package for " + mPackageName);
}
// validate split names marked for removal
for (String splitName : removeSplitList) {
if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Split not found: " + splitName);
}
}
// ensure we've got appropriate package name, version code and signatures
if (mPackageName == null) {
mPackageName = pkgInfo.packageName;
mVersionCode = pkgInfo.versionCode;
}
if (mSignatures == null) {
mSignatures = pkgInfo.signatures;
}
}
//PackageManagerShellCommand makeInstallParams 在初始化就赋值SessionParams.MODE_FULL_INSTALL
if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Full installs must include a base package
if (!stagedSplits.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Full install must include a base package");
}
} else {
// Partial installs must be consistent with existing install
if (pkgInfo == null || pkgInfo.applicationInfo == null) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Missing existing base package for " + mPackageName);
}
final PackageLite existing;
final ApkLite existingBase;
ApplicationInfo appInfo = pkgInfo.applicationInfo;
try {
existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
assertApkConsistentLocked("Existing base", existingBase);//包名版本的信息检测
// Inherit base if not overridden
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
mResolvedInheritedFiles.add(mResolvedBaseFile);
}
// Inherit splits if not overridden
if (!ArrayUtils.isEmpty(existing.splitNames)) {
for (int i = 0; i < existing.splitNames.length; i++) {
final String splitName = existing.splitNames[i];
Log.i(" PackageManagerService-xiao", "PackageInstallerSession validateInstallLocked splitName :"+splitName);
final File splitFile = new File(existing.splitCodePaths[i]);
final boolean splitRemoved = removeSplitList.contains(splitName);
if (!stagedSplits.contains(splitName) && !splitRemoved) {
mResolvedInheritedFiles.add(splitFile);
}
}
}
// Inherit compiled oat directory.
final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
mInheritedFilesBase = packageInstallDir;
final File oatDir = new File(packageInstallDir, "oat");
//解析odx
if (oatDir.exists()) {
final File[] archSubdirs = oatDir.listFiles();
// Keep track of all instruction sets we've seen compiled output for.
// If we're linking (and not copying) inherited files, we can recreate the
// instruction set hierarchy and link compiled output.
if (archSubdirs != null && archSubdirs.length > 0) {
final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
for (File archSubDir : archSubdirs) {
// Skip any directory that isn't an ISA subdir.
if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
continue;
}
mResolvedInstructionSets.add(archSubDir.getName());
List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
// Only add compiled files associated with the base.
// Once b/62269291 is resolved, we can add all compiled files again.
for (File oatFile : oatFiles) {
if (oatFile.getName().equals("base.art")
|| oatFile.getName().equals("base.odex")
|| oatFile.getName().equals("base.vdex")) {
mResolvedInheritedFiles.add(oatFile);
}
}
}
}
}
}
}
现在我们来看看MSG_COMMIT做什么?就是直接调用commitLocked
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_COMMIT:
synchronized (mLock) {
try {
commitLocked();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
Slog.e(TAG,
"Commit of session " + sessionId + " failed: " + completeMsg);
destroyInternal();
dispatchSessionFinished(e.error, completeMsg, null);
}
}
private void commitLocked()
throws PackageManagerException {
if (mDestroyed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
}
if (!mSealed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
}
Preconditions.checkNotNull(mPackageName);
Preconditions.checkNotNull(mSignatures);
Preconditions.checkNotNull(mResolvedBaseFile);
//needToAskForPermissionsLocked 是否具有静默安装权限
if (needToAskForPermissionsLocked()) {
// User needs to accept permissions; give installer an intent they
// can use to involve user.
//发送广播权限已经被确认好了
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) {
}
// Commit was keeping session marked as active until now; release
// that extra refcount so session appears idle.
closeInternal(false);
return;
}
if (stageCid != null) {
// Figure out the final installed size and resize the container once
// and for all. Internally the parser handles straddling between two
// locations when inheriting.
final long finalSize = calculateInstalledSize();
resizeContainer(stageCid, finalSize);
}
// Inherit any packages and native libraries from existing install that
// haven't been overridden.
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
try {
final List<File> fromFiles = mResolvedInheritedFiles;
final File toDir = resolveStageDirLocked();
if (LOGD) Log.d("PackageManagerService-xiao", "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");
createOatDirs(mResolvedInstructionSets, oatDir);
}
linkFiles(fromFiles, toDir, mInheritedFilesBase);
} else {
// TODO: this should delegate to DCS so the system process
// avoids holding open FDs into containers.
copyFiles(fromFiles, toDir);
}
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Failed to inherit existing install", e);
}
}
// TODO: surface more granular state from dexopt
mInternalProgress = 0.5f;
computeProgressLocked(true);
// Unpack native libraries
extractNativeLibraries(mResolvedStageDir, params.abiOverride);//拷贝外部的库
// Container is ready to go, let's seal it up!
if (stageCid != null) {
finalizeAndFixContainer(stageCid);
}
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
destroyInternal();//删除stageDir临时文件
dispatchSessionFinished(returnCode, msg, extras);
}
};
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,
mInstallerPackageName, mInstallerUid, user, mCertificates);
}
确认安装权限和安装位置之后调用PackageManagerService.installStage。大家有没有一种恍然大悟的感觉,之前所做的所有事情最后都是会回到PackageManagerService,由它来扫描安装apk。那之后的过程跟我们之前讲述的系统扫描是否会相同呢?
void installStage(String packageName, File stagedDir, String stagedCid,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
if (true) {
if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
Log.d(TAG, "Ephemeral install of " + packageName);
}
}
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);
}
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);
}
创建安装参数InstallParams,发送安装广播INIT_COPY。
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
// idx为当前需要安装的APK个数,mPendingInstalls里面保存所有需要安装的APK解析出来的HandlerParams参数
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Log.i(TAG, "doHandleMessage 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) {
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.
/*
APK的安装居然需要使用另外一个APK提供的服务,该服务就是
DefaultContainerService,由DefaultCotainerService.apk提供,
下面的connectToService函数将调用bindService来启动该服务
*/
if (!connectToService()) {
Log.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 {//服务启动完
// Once we bind to the service, the first
// pending request will be processed.
mPendingInstalls.add(idx, params);
}
} else {
mPendingInstalls.add(idx, params);
// Already bound to the service. Just make
// sure we trigger off processing the first request.
//启动安装
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
case MCS_BOUND: {
if (DEBUG_INSTALL) Log.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) {
if (!mBound) {
// Something seriously wrong since we are not bound and we are not
// waiting for connection. Bail out.
Log.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();//如果没法启动该service,则不能安装程序
} else {
Log.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
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()) {
// 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.remove(0);//删除队列头
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting delayed MCS_UNBIND");
//如果安装请求都处理完了,则需要和Service断绝联系,
//通过发送MSC_UNB消息处理断交请求。
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// Unbind after a little delay, to avoid
// continual thrashing.
sendMessageDelayed(ubmsg, 10000);
}
} else {
// 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.
Log.w(TAG, "Empty queue");
}
break;
}
doHandleMessage 处理INIT_COPY广播主要做了哪些事情。
1.连接DefaultCotainerService服务,把刚才send的信息添加到 mPendingInstalls.add(idx, params)。发送mHandler.sendEmptyMessage(MCS_BOUND)广播。
2.执行params.startCopy(),params就是之前InstallParams。
HandlerParams和InstallArgs介绍
除了HandlerParams家族外,这里提前请出另外一个家族InstallArgs及其成员,如图4-8所示。
:-:
图4-8 HandlerParams及InstallArgs家族成员
由图4-8可知:
- HandlerParams和InstallArgs均为抽象类。
- HandlerParams有三个子类,分别是InstallParams、MoveParams和MeasureParams。其中,InstallParams用于处理APK的安装,MoveParams用于处理某个已安装APK的搬家请求(例如从内部存储移动到SD卡上),MeasureParams用于查询某个已安装的APK占据存储空间的大小(例如在设置程序中得到的某个APK使用的缓存文件的大小)。
- 对于InstallParams来说,它还有两个伴儿,即InstallArgs的派生类FileInstallArgs和SdInstallArgs。其中,FileInstallArgs针对的是安装在内部存储的APK,而SdInstallArgs针对的是那些安装在SD卡上的APK。
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Log.i(TAG, "HandlerParams startCopy " + mUser + ": " + this);
//MAX_RETIRES目前为4,表示尝试4次安装,如果还不成功,则认为安装失败
if (++mRetries > MAX_RETRIES) {
Log.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) Log.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
handleReturnCode();
return res;
}
在上述代码中,基类的startCopy将调用子类实现的handleStartCopy和handleReturnCode函数。下面来看InstallParams是如何实现这两个函数的。先来看派生类InstallParams的handleStartCopy函数
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
Log.i(" PackageManagerService-xiao", "PackageManagerService handleStartCopy origin.staged:"+origin.staged);
// If we're already staged, we've firmly committed to an install location
// 是安装在手机内部存储空间还是sdcard中,设置对应标志位
// 新安装的情况下stage为true,也就是默认内部存储
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;//安装到sd卡
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;//安装到内部存储
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
// 检查APK的安装位置是否正确
if (onInt && onSd) {//不能同时安装到内部和外部
// Check if both bits are set.
Log.w(TAG, "Conflicting flags specified for installing on both internal and external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (onSd && ephemeral) {
Log.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) {
Log.v(TAG, "pkgLite for install: " + pkgLite);
}
/*
* If we have too little free space, try to free cache
* before giving up.
*/
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);
//从DSMS查询内部空间最小余量,默认是总空间的10%
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) {
Log.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) {
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 {
/// M: Removable system app support
installFlags = sPmsExt.customizeInstallPkgFlags(installFlags, pkgLite,
mSettings.mPackages, getUser());
// Override with defaults if needed.
//②根据DCS返回的安装路径,还需要调用installLocationPolicy进行检查
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) {
Log.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
installFlags |= PackageManager.INSTALL_INSTANT_APP;
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;
}
}
}
}
//③创建一个安装参数对象,对于安装位置为内部存储的情况,args的真实类型为FileInstallArgs
final InstallArgs args = createInstallArgs(this);
mArgs = args;
if (ret == PackageManager.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());
final int installerUid =
verificationInfo == null ? -1 : verificationInfo.installerUid;
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(
verifierUser.getIdentifier(), installFlags, installerUid)) {
// 对当前包做验证操作
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(),
false /*allowDynamicSplits*/);
if (DEBUG_VERIFY) {
Log.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);
DeviceIdleController.LocalService idleController = getDeviceIdleController();
final long idleDuration = getVerificationTimeout();
/*
* 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) {
Log.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);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
verifierComponent.getPackageName(), idleDuration,
verifierUser.getIdentifier(), false, "package verifier");
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);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
mRequiredVerifierPackage, idleDuration,
verifierUser.getIdentifier(), false, "package verifier");
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 {
/*
* No package verification is enabled, so immediately start
* the remote call to initiate copy using temporary file.
*/
//调用args的copyApk函数
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
在以上代码中,一共列出了五个关键点,总结如下:
- 调用DCS的getMinimalPackageInfo函数,将得到一个PackageLite对象,该对象是一个轻量级的用于描述APK的结构(相比PackageParser.Package来说)。在这段代码逻辑中,主要想取得其recommendedInstallLocation的值。此值表示该APK推荐的安装路径。
- 调用installLocationPolicy检查推荐的安装路径。例如系统Package不允许安装在SD卡上。
- createInstallArgs将根据安装位置创建不同的InstallArgs。如果是内部存储,则返回FileInstallArgs,否则为SdInstallArgs。
- 在正式安装前,应先对该APK进行必要的检查。这部分代码后续再介绍。
- 调用InstallArgs的copyApk。对本例来说,将调用FileInstallArgs的copyApk函数。
DefaultContainerService.java::getMinimalPackageInfo函数
public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
String abiOverride) {
final Context context = DefaultContainerService.this;
final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
PackageInfoLite ret = new PackageInfoLite();
if (packagePath == null) {
Slog.i(TAG, "Invalid package file " + packagePath);
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
return ret;
}
final File packageFile = new File(packagePath);
final PackageParser.PackageLite pkg;
final long sizeBytes;
try {
pkg = PackageParser.parsePackageLite(packageFile, 0);
sizeBytes = PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
} catch (PackageParserException | IOException e) {
Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
if (!packageFile.exists()) {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
} else {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
}
return ret;
}
final int recommendedInstallLocation;
final long token = Binder.clearCallingIdentity();
try {
//调用recommendAppInstallLocation,取得一个合理的安装位置PackageHelper.RECOMMEND_INSTALL_INTERNAL 或者RECOMMEND_INSTALL_EXTERNAL
recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
pkg.packageName, pkg.installLocation, sizeBytes, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
ret.packageName = pkg.packageName;
ret.splitNames = pkg.splitNames;
ret.versionCode = pkg.versionCode;
ret.baseRevisionCode = pkg.baseRevisionCode;
ret.splitRevisionCodes = pkg.splitRevisionCodes;
ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers;
ret.recommendedInstallLocation = recommendedInstallLocation;
ret.multiArch = pkg.multiArch;
return ret;
}
@Override
public ObbInfo getObbInfo(String filename) {
try {
return ObbScanner.getObbInfo(filename);
} catch (IOException e) {
Slog.d(TAG, "Couldn't get OBB info for " + filename);
return null;
}
}
APK可在AndroidManifest.xml中声明一个安装位置,不过DCS除了解析该位置外,还需要做进一步检查,这个工作由recommendAppInstallLocation函数完成,代码如下
@Deprecated
public static int resolveInstallLocation(Context context, String packageName,
int installLocation, long sizeBytes, int installFlags) {
final SessionParams params = new SessionParams(SessionParams.MODE_INVALID);
params.appPackageName = packageName;
params.installLocation = installLocation;
params.sizeBytes = sizeBytes;
params.installFlags = installFlags;
try {
return resolveInstallLocation(context, params);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public static int resolveInstallLocation(Context context, SessionParams params)
throws IOException {
ApplicationInfo existingInfo = null;
try {
existingInfo = context.getPackageManager().getApplicationInfo(params.appPackageName,
PackageManager.MATCH_ANY_USER);
} catch (NameNotFoundException ignored) {
}
final int prefer;
final boolean checkBoth;
boolean ephemeral = false;
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
prefer = RECOMMEND_INSTALL_INTERNAL;
ephemeral = true;
checkBoth = false;
} else if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
prefer = RECOMMEND_INSTALL_INTERNAL;
checkBoth = false;
} else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
prefer = RECOMMEND_INSTALL_EXTERNAL;
checkBoth = false;
} else if (params.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
prefer = RECOMMEND_INSTALL_INTERNAL;
checkBoth = false;
} else if (params.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
prefer = RECOMMEND_INSTALL_EXTERNAL;
checkBoth = true;
} else if (params.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {//一般设定的位置为AUTO,默认是内部空间
// When app is already installed, prefer same medium
if (existingInfo != null) {
// TODO: distinguish if this is external ASEC
if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
prefer = RECOMMEND_INSTALL_EXTERNAL;
} else {
prefer = RECOMMEND_INSTALL_INTERNAL;
}
} else {
prefer = RECOMMEND_INSTALL_INTERNAL;
}
checkBoth = true;
} else {
prefer = RECOMMEND_INSTALL_INTERNAL;
checkBoth = false;
}
boolean fitsOnInternal = false;
if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
fitsOnInternal = fitsOnInternal(context, params);
}
boolean fitsOnExternal = false;
if (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) {
fitsOnExternal = fitsOnExternal(context, params);
}
if (prefer == RECOMMEND_INSTALL_INTERNAL) {
// The ephemeral case will either fit and return EPHEMERAL, or will not fit
// and will fall through to return INSUFFICIENT_STORAGE
if (fitsOnInternal) {
return (ephemeral)
? PackageHelper.RECOMMEND_INSTALL_EPHEMERAL
: PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
} else if (prefer == RECOMMEND_INSTALL_EXTERNAL) {
if (fitsOnExternal) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
if (checkBoth) {
if (fitsOnInternal) {
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else if (fitsOnExternal) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
DCS的getMinimalPackageInfo函数为了得到一个推荐的安装路径做了不少工作,其中,各种安装策略交叉影响。这里总结一下相关的知识点:
- APK在AndroidManifest.xml中设置的安装点默认为AUTO,在具体对应时倾向内部空间。
- 用户在Settings数据库中设置的安装位置。
- 检查外部存储或内部存储是否有足够空间
PackageManagerService.java::InstallArgs.copyApk函数
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk(imcs, temp);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
/*
本例中temp参数为true,createCopyFile将在/data/app下创建一个临时文件。
临时文件名为vmdl-随机数.tmp。为什么会用这样的文件名呢?
因为PKMS通过Linux的inotify机制监控了/data/app,目录,如果新复制生成的文件名后缀
为apk,将触发PKMS扫描。为了防止发生这种情况,这里复制生成的文件才有了
如此奇怪的
*/
//文件以及拷贝完成就不需要再拷贝
if (origin.staged) {
if (DEBUG_INSTALL) Log.d(TAG, origin.file + " already staged; skipping copy temp:"+temp);
codeFile = origin.file;
resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
// 创建目录 /data/app/vmdl1054430479.tmp/
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
Log.i("PackageManagerService-xiao", "PackageManagerService FileInstallArgs tempDir:"+tempDir.getAbsolutePath());
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Log.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
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;
// 真正的文件拷贝
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Log.e(TAG, "Failed to copy package");
return ret;
}
// 获取库的跟目录
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
// 拷贝 Native代码 即so文件
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
abiOverride);
} catch (IOException e) {
Log.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
4. handleReturnCode分析
在HandlerParams的startCopy函数中,handleStartCopy执行完之后,将调用handleReturnCode开展后续工作,代码如下:
PackageManagerService.java::InstallParams.HandleParams
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);
}
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
// Queue up an async operation since the package installation may take a little while.
// 向mHandler中发送一个Runnable对象,这里是异步操作,因为安装一个程序包可能需要一些时间
//一般currentStatus=1
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);// 清除任务
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo(); // 创建一个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) {
// 安装阶段,调用installPackageLI进行安装
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;//计算一个ID号
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
PostInstallData data = new PostInstallData(args, res);
mRunningInstalls.put(token, data);//保存到mRunningInstalls结构中,以token为key
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) {
Log.e(TAG, "Exception trying to enqueue restore", e);
doRestore = false;
}
} else {
Log.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);
//抛一个POST_INSTALL消息给mHandler进行处理 adb 等待安装结果
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
});
}
由上面代码可知,handleReturnCode主要做了4件事情:
- 调用InstallArgs的doPreInstall函数,在本例中是FileInstallArgs的doPreInstall函数。
- 调用PKMS的installPackageLI函数进行APK安装,该函数内部将调用InstallArgs的doRename对临时文件进行改名。另外,还需要扫描此APK文件。此过程和之前介绍的“扫描系统Package”一节的内容类似。至此,该APK中的私有财产就全部被登记到PKMS内部进行保存了。
- 调用InstallArgs的doPostInstall函数,在本例中是FileInstallArgs的doPostInstall函数。
- 此时,该APK已经安装完成(不论失败还是成功),继续向mHandler抛送一个POST_INSTALL消息,该消息携带一个token,通过它可从mRunningInstalls数组中取得一个PostInstallData对象
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);
}
}
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
Log.i(" PackageManagerService-xiao", "PackageManagerService installPackageLI");
//获取 installFlags属性,这个属性表明APP安装到哪里
final int installFlags = args.installFlags;
// 安装包应用程序的 包名
final String installerPackageName = args.installerPackageName;
// volume的Uuid
final String volumeUuid = args.volumeUuid;
//根据安装包代码的路径生成一个临时文件
final File tmpPackageFile = new File(args.getCodePath());
final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
// 是否安装到外部存储
final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
|| (args.volumeUuid != null));
// 新安装还是更新安装的标志位
final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
final boolean virtualPreload =
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
boolean replace = false;
int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
if (args.move != null) {
// moving a complete application; perform an initial scan on the new install location
scanFlags |= SCAN_INITIAL;
}
if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
scanFlags |= SCAN_DONT_KILL_APP;
}
if (instantApp) {
scanFlags |= SCAN_AS_INSTANT_APP;
}
if (fullApp) {
scanFlags |= SCAN_AS_FULL_APP;
}
if (virtualPreload) {
scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
}
// Result object to be returned
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
res.installerPackageName = installerPackageName;
if (DEBUG_INSTALL) Log.d(TAG, "installPackageLI: path=" + tmpPackageFile);
// Sanity check
if (instantApp && (forwardLocked || onExternal)) {
Log.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
+ " external=" + onExternal);
res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
return;
}
// Retrieve PackageSettings and parse package
// 获取解析包配置的标志位
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
| (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)
| (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
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 {
// 解析APK,主要是解析AndroidManifest.xml文件,将结果记录在PackageParser.Package中
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
//sdk版本检查
if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
Log.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) {
Log.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()) {
// Static shared libraries have synthetic package names
renameStaticSharedLibraryPackage(pkg);
// No static shared libs on external storage
if (onExternal) {
Log.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;
}
}
// If we are installing a clustered package add results for the children
Log.i(" PackageManagerService-xiao", "PackageManagerService installPackageLI pkg.childPackages:"+pkg.childPackages);
//一个APK拆分成几个apk的情况
if (pkg.childPackages != null) {
synchronized (mPackages) {
final int childCount = pkg.childPackages.size();
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
PackageInstalledInfo childRes = new PackageInstalledInfo();
childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
childRes.pkg = childPkg;
childRes.name = childPkg.packageName;
PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRes.origUsers = childPs.queryInstalledUsers(
sUserManager.getUserIds(), true);
}
if ((mPackages.containsKey(childPkg.packageName))) {
childRes.removedInfo = new PackageRemovedInfo(this);
childRes.removedInfo.removedPackage = childPkg.packageName;
childRes.removedInfo.installerPackageName = childPs.installerPackageName;
}
if (res.addedChildPackages == null) {
res.addedChildPackages = new ArrayMap<>();
}
res.addedChildPackages.put(childPkg.packageName, childRes);
}
}
}
// If package doesn't declare API override, mark that we have an install
// time CPU ABI override.
if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
pkg.cpuAbiOverride = args.abiOverride;
}
String pkgName = res.name = pkg.packageName;
// 如果这个待安装的APP不是测试包,但是如果环境为仅允许测试包则返回
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
return;
}
}
try {
// either use what we've been given or parse directly from the APK
if (args.certificates != null) {
try {
PackageParser.populateCertificates(pkg, args.certificates);
} catch (PackageParserException e) {
// there was something wrong with the certificates we were given;
// try to pull them from the APK
PackageParser.collectCertificates(pkg, parseFlags);
}
} else {
PackageParser.collectCertificates(pkg, parseFlags);
}
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
}
// Get rid of all references to package scan path via parser.
pp = null;
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
// Check if installing already existing package
// 如果安装的升级应用,继续使用以前的老包名
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
Log.i(" PackageManagerService-xiao", "PackageManagerService installPackageLI PackageManager.INSTALL_REPLACE_EXISTING");
String oldName = mSettings.getRenamedPackageLPr(pkgName);
if (pkg.mOriginalPackages != null
&& pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
// This package is derived from an original package,
// and this device has been updating from that original
// name. We must continue using the original name, so
// rename the new package here.
// 如果要进行安装的应用,已经存在,将是替换安装,则设置replace=true
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;
if (DEBUG_INSTALL) Log.d(TAG, "Replacing existing renamed package: oldName="
+ oldName + " pkgName=" + pkgName);
} else if (mPackages.containsKey(pkgName)) {
// This package, under its official name, already exists
// on the device; we should replace it.
replace = true;
if (DEBUG_INSTALL) Log.d(TAG, "Replace existing pacakge: " + pkgName);
}
// Child packages are installed through the parent package
if (pkg.parentPackage != null) {
res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Package " + pkg.packageName + " is child of package "
+ pkg.parentPackage.parentPackage + ". Child packages "
+ "can be updated only through the parent package.");
return;
}
if (replace) {
// Prevent apps opting out from runtime permissions
// 如果是替换,即升级安装
PackageParser.Package oldPackage = mPackages.get(pkgName);
final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
// 如果老的TargetSdk 大于android 5.1 而新的TargetSdk 小于5.1,
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;
}
// Prevent apps from downgrading their targetSandbox.
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;
}
// Prevent installing of child packages
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;
}
}
}
PackageSetting ps = mSettings.mPackages.get(pkgName);
// 如果 ps 不为null,同样说明,已经存在一个具有相同安装包包名的程序,被安装,所以还是处理覆盖安装的问题。
// 这里主要验证包名的签名,不一致的话,是不能覆盖安装的,另外版本号也不能比安装的地,否则不能替换安装
if (ps != null) {
if (DEBUG_INSTALL) Log.d(TAG, "Existing package: " + ps);
// Static shared libs have same package with different versions where
// we internally use a synthetic package name to allow multiple versions
// of the same package, therefore we need to compare signatures against
// the package setting for the latest library version.
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
if (libraryEntry != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
}
}
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
//检查密钥集合是否一致
if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
return;
}
} else {
try {
verifySignaturesLP(signatureCheckPs, pkg);
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
}
}
// 判断安装的应用是否存在同名的应用,如果存在,判断应用是否带有系统应用的标志
oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
// 检查APK中定义的所有的权限是否已经被其他应用定义了,如果重定义的是系统应用定义的权限,
//那么忽略本app定义的这个权限。如果重定义的是非系统引用的权限,那么本次安装就以失败返回。
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
// Don't allow anyone but the system to define ephemeral permissions.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
&& !systemApp) {
Log.w(TAG, "Non-System package " + pkg.packageName
+ " attempting to delcare ephemeral permission "
+ perm.info.name + "; Removing ephemeral.");
perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
}
// Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final boolean sigsOk;
if (bp.sourcePackage.equals(pkg.packageName)
&& (bp.packageSetting instanceof PackageSetting)
&& (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,
scanFlags))) {
sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
} else {
sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
if (!bp.sourcePackage.equals("android")) {
res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ pkg.packageName + " attempting to redeclare permission "
+ perm.info.name + " already owned by " + bp.sourcePackage);
res.origPermission = perm.info.name;
res.origPackage = bp.sourcePackage;
return;
} else {
Log.w(TAG, "Package " + pkg.packageName
+ " attempting to redeclare system permission "
+ perm.info.name + "; ignoring new declaration");
pkg.permissions.remove(i);
}
} else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
// Prevent apps to change protection level to dangerous from any other
// type as this would allow a privilege escalation where an app adds a
// normal/signature permission in other app's group and later redefines
// it as dangerous leading to the group auto-grant.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS) {
if (bp != null && !bp.isRuntime()) {
Log.w(TAG, "Package " + pkg.packageName + " trying to change a "
+ "non-runtime permission " + perm.info.name
+ " to runtime; keeping old protection level");
perm.info.protectionLevel = bp.protectionLevel;
}
}
}
}
}
}
/// M: Operator APP support
// 如果是带带有系统应用标志的应用,却要安装在SD卡上,则报错返回,安装失败原因错误的安装路径
if (systemApp || sPmsExt.isOperatorApp(mPackages, mSettings.mPackages, pkgName)) {
if (onExternal) {
// Abort update; system app can't be replaced with app on sdcard
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
return;
} else if (instantApp) {
// Abort update; system app can't be replaced with an instant app
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Cannot update a system app with an instant app");
return;
}
}
// 如果是移动APP
Log.i(" PackageManagerService-xiao", "installPackageLI args.move"+args.move);
if (args.move != null) {
// We did an in-place move, so dex is ready to roll
scanFlags |= SCAN_NO_DEX;
scanFlags |= SCAN_MOVE;
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps == null) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
"Missing settings for moved package " + pkgName);
}
// We moved the entire application as-is, so bring over the
// previously derived ABI information.
pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
}
} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {//安装apk的情况
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
scanFlags |= SCAN_NO_DEX;
try {
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
extractNativeLibs, mAppLib32InstallDir);
} catch (PackageManagerException pme) {
Log.e(TAG, "Error deriving application ABI", pme);
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
return;
}
// Shared libraries for the package need to be updated.
synchronized (mPackages) {
try {
updateSharedLibrariesLPr(pkg, null);//更新sharedlib库
} catch (PackageManagerException e) {
Log.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
}
}
// 重命名,将/data/app/vmdl{安装会话}.tmp重命名为data/app/包名-suffix
// /data/app/vmdl636355084.tmp to /data/app/kr.hwangti.batterylog-D9rVNrKDGBnxt7CIXwcJyg==
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}
Log.d(TAG, " installPackageLI instantApp: " + instantApp);
if (!instantApp) {
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
Log.d(TAG, "Not verifying instant app install for app links: " + pkgName);
}
}
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static libs have a synthetic package name containing the version
// and cannot be updated as an update would get a new package name,
// unless this is the exact same version code which is useful for
// development.
PackageParser.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 {
// 首次安装
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
// Check whether we need to dexopt the app.
//
// NOTE: it is IMPORTANT to call dexopt:
// - after doRename which will sync the package data from PackageParser.Package and its
// corresponding ApplicationInfo.
// - after installNewPackageLIF or replacePackageLIF which will update result with the
// uid of the application (pkg.applicationInfo.uid).
// This update happens in place!
//
// We only need to dexopt if the package meets ALL of the following conditions:
// 1) it is not forward locked.
// 2) it is not on on an external ASEC container.
// 3) it is not an instant app or if it is then dexopt is enabled via gservices.
//
// Note that we do not dexopt instant apps by default. dexopt can take some time to
// complete, so we skip this step during installation. Instead, we'll take extra time
// the first time the instant app starts. It's preferred to do it this way to provide
// continuous progress to the useur instead of mysteriously blocking somewhere in the
// middle of running an instant app. The default behaviour can be overridden
// via gservices.
final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
&& !forwardLocked
&& !pkg.applicationInfo.isExternalAsec()
&& (!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
if (performDexopt) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
// Do not run PackageDexOptimizer through the local performDexOpt
// method because `pkg` may not be in `mPackages` yet.
//
// Also, don't fail application installs if the dexopt step fails.
DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE);
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
// BackgroundDexOptService will remove it from its blacklist.
// TODO: Layering violation
BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
ps.setUpdateAvailable(false /*updateAvailable*/);
}
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRes.newUsers = childPs.queryInstalledUsers(
sUserManager.getUserIds(), true);
}
}
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
updateSequenceNumberLP(ps, res.newUsers);
updateInstantAppInstallerLocked(pkgName);
}
}
}
POST_INSTALL处理
case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
// 我们知道msg的arg1是token,arg2是0
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;
// 如果已经成功的安装了应用,在发送广播之前先授予一些必要的权限
// 这些权限在 installPackageAsUser 中创建 InstallParams 时传递的,为null。
//INSTALL_GRANT_RUNTIME_PERMISSIONS 这个属性在PackageManagerShellCommand.java 参数是-g给予的
final boolean grantPermissions = (args.installFlags
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
final boolean killApp = (args.installFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
final boolean virtualPreload = ((args.installFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
final String[] grantedPermissions = args.installGrantPermissions;
// Handle the parent package
handlePackagePostInstall(parentRes, grantPermissions, killApp,
virtualPreload, 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,
virtualPreload, grantedPermissions, false /*didRestore*/,
args.installerPackageName, args.observer);
}
// Log tracing if needed
if (args.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
} else {
Log.e(TAG, "Bogus post-install token " + msg.arg1);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
boolean killApp, boolean virtualPreload, 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. Also
// for legacy apps in permission review mode we clear the permission
// review flag which is used to emulate runtime permissions for
// legacy apps.
//动态权限的检查
if (grantPermissions) {
grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
}
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
final String installerPackageName =
res.installerPackageName != null
? res.installerPackageName
: res.removedInfo != null
? res.removedInfo.installerPackageName
: null;
/// M: CTA requirement - permission control @{
grantCtaRuntimePerm(update, res);
//@}
// 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) {
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
final String packageName = res.pkg.applicationInfo.packageName;
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
int[] firstUsers = EMPTY_INT_ARRAY;
int[] updateUsers = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
for (int newUser : res.newUsers) {
if (ps.getInstantApp(newUser)) {
continue;
}
if (allNewUsers) {
firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
continue;
}
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 package is not a static shared lib.
if (res.pkg.staticSharedLibName == null) {
mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.applicationInfo.isSystemApp();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUsers);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
//发送一个广播,apk安装完成
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/, updateUsers);
///M: MTK Power: Disable installation boost
if (mPowerHalManager != null) {
mPowerHalManager.setInstallationBoost(false);
}
if (installerPackageName != null) {
//发送一个更新的广播
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/, updateUsers);
}
// Send replaced for users that don't see the package for the first time
if (update) {
//apk升级
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUsers);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
installerPackageName, 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) {
Log.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)) {
if (DEBUG_INSTALL) {
Log.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 this app is a browser and it's newly-installed for some
// users, clear any default-browser state in those users. The
// app's nature doesn't depend on the user, so we can just check
// its browser nature in any user and generalize.
if (packageIsBrowser(packageName, userId)) {
mSettings.setDefaultBrowserPackageNameLPw(null, userId);
}
// We may also need to apply pending (restored) runtime
// permission grants within these users.
mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
}
}
}
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
// Remove the replaced package's older resources safely now
// We delete after a gc for applications on sdcard.
if (res.removedInfo != null && res.removedInfo.args != null) {
Runtime.getRuntime().gc();
synchronized (mInstallLock) {
res.removedInfo.args.doPostDeleteLI(true);
}
} else {
// Force a gc to clear up things. Ask for a background one, it's fine to go on
// and not block here.
VMRuntime.getRuntime().requestConcurrentGC();
}
// Notify DexManager that the package was installed for new users.
// The updated users should already be indexed and the package code paths
// should not change.
// Don't notify the manager for ephemeral apps as they are not expected to
// survive long enough to benefit of background optimizations.
for (int userId : firstUsers) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
// There's a race currently where some install events may interleave with an uninstall.
// This can lead to package info being null (b/36642664).
if (info != null) {
mDexManager.notifyPackageInstalled(info, userId);
/// M: Removable system app support
sPmsExt.onPackageAdded(packageName, userId);
}
}
}
// If someone is watching installs - notify them
if (installObserver != null) {
try {
Bundle extras = extrasForInstallResult(res);
installObserver.onPackageInstalled(res.name, res.returnCode,
res.returnMsg, extras);
} catch (RemoteException e) {
Log.i(TAG, "Observer no longer exists.");
}
}
}
运行到这里整个apk的安装就完成了,如果需要增加app的动态权限可以在handlePackagePostInstall里面实现。
更多推荐
所有评论(0)