关于pm命令安装,其copy过程与下载安装不同,但安装过程却与下载过程是相同的,这里不做重复分析。
拷贝过程流程图
pm的入口在com.android.commands.pm.Pm类,那么这是如何调用到这个类的呢,这是adb命令通过adbd守护进程调用到/system/bin/pm这个脚本,其脚本源码如下:
base=/system
export CLASSPATh-$base/framework/pm.jar
exec app_process $base/bin.com.android.commands.pm.Pm "$@"
Pm类通过脚本启动,执行顺序是main->run->runInstall,然后提交session。
public static void main(String[] args) {
int exitCode = 1;
try {
exitCode = new Pm().run(args);
} catch (Exception e) {
Log.e(TAG, "Error", e);
System.err.println("Error: " + e);
if (e instanceof RemoteException) {
System.err.println(PM_NOT_RUNNING_ERR);
}
}
System.exit(exitCode);
}
public int run(String[] args) throws RemoteException {
boolean validCommand = false;
if (args.length < 1) {
return showUsage();
}
mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (mPm == null) {
System.err.println(PM_NOT_RUNNING_ERR);
return 1;
}
mInstaller = mPm.getPackageInstaller();
mArgs = args;
String op = args[0];
mNextArg = 1;
//......
//安装
if ("install".equals(op)) {
return runInstall();
}
if ("uninstall".equals(op)) {
return runUninstall();
}
//.....
}
Pm.runInstall中首先是创建session,然后提交session,代码如下。
private int runInstall() throws RemoteException {
long startedTime = SystemClock.elapsedRealtime();
//创建安装参数
final InstallParams params = makeInstallParams();
//app路径
final String inPath = nextArg();
if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
File file = new File(inPath);
if (file.isFile()) {
try {
//轻量级解析
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;
}
}
//创建一个session id
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
try {
//copy文件
if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
//提交session
Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
if (status.second != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
return 0;
} finally {
try {
mInstaller.abandonSession(sessionId);
} catch (Exception ignore) {
}
}
}
接下来看doCommitSession,根据id创建PackageInstallerSession的客户端调用commit
//PM.commit
private Pair<String, Integer> doCommitSession(int sessionId, boolean logSuccess)
throws RemoteException {
PackageInstaller.Session session = null;
try {
//根据session id 创建session
session = new PackageInstaller.Session(
mInstaller.openSession(sessionId));
final LocalIntentReceiver receiver = new LocalIntentReceiver();
//跨进程提交会调用PackageInstallerSession.commit
session.commit(receiver.getIntentSender());
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status);
} finally {
IoUtils.closeQuietly(session);
}
}
commit 内部发一个消息,然后调用commitLocked
//PackageInstallerSession.commit
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
final boolean wasSealed;
synchronized (mLock) {
//.....
mCommitted = true;
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_COMMIT:
synchronized (mLock) {
try {
//内部调用commitLocked
commitLocked();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
destroyInternal();
dispatchSessionFinished(e.error, completeMsg, null);
}
}
break;
}
return true;
}
//PackageInstallerSession.commitLocked
private void commitLocked()
throws PackageManagerException {
// Unpack native libraries
extractNativeLibraries(mResolvedStageDir, params.abiOverride);
// Container is ready to go, let's seal it up!
if (stageCid != null) {
finalizeAndFixContainer(stageCid);
}
//.......
mRelinquished = true;
//调用PMS的installStage
mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
mInstallerPackageName, mInstallerUid, user, mCertificates);
}
回到了PMS.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);
}
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;
//发送INIT_COPY
mHandler.sendMessage(msg);
}
发送完Handler消息后就与下载安装过程相同了。请参考:Android PackageManagerService(二)下载安装详解