PMS 在创建的时候创建了PackageInstallerService,所以在安装应用之前先了解一下 PackageInstallerService :用于管理安装的服务
附带的是 Android 9.0 的源码
管理会话的服务 - PackageInstallerService
- PackageInstallerService 主要用于管理安装会话服务,可以通过 PackageInstallerService 分配一个 SessionId,这个系统唯一的安装 id 代表一次安装过程,如果一个应用安装需要几个步骤完成,即使设备重启了,也可以通过这个ID继续完成安装。
- PackageInstallerService 中提供了 createSession() 创建一个 Session
@Override
public int createSession(SessionParams params, String installerPackageName, int userId) {
try {
return createSessionInternal(params, installerPackageName, userId);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
}
createSession() 将会返回一个系统唯一值作为 Session ID 。如果希望再次使用这个 Session ID 可以同过 openSession() 去打开它;
@Override
public IPackageInstallerSession openSession(int sessionId) {
try {
return openSessionInternal(sessionId);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
}
openSession() 返回一个 IPackageInstallerSession 对象,它是 Binder 服务 PackageInstallerSession 的 IBinder 对象。每一个 Install Session 都会在 SystemServer 中有一个对应的 PackageInstallerSession 对象。在 PackageInstallerService 中的 mSessions 数组中保存了所有 PackageInstallerSession 对象
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
- 在系统初始化的时候,PMS会创建 PackageInstallerService 服务,在创建这个服务时,会读取 /data/system/ 目录下的 install_session.xml 文件
mSessionsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
"package-session");
这个文件中保存了系统中未完成的 Install Session 。然后PackageInstallerService 会通过文件内容创建 PackageInstallerSession对象并插入到 mSessions 中。PackageInstallerSession 中保存了应用安装的相关数据如路径、进度、中间数据保存等。
// 解析 xml 文件
private void writeSessionsLocked() {
FileOutputStream fos = null;
try {
fos = mSessionsFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, StandardCharsets.UTF_8.name());
out.startDocument(null, true);
out.startTag(null, TAG_SESSIONS);
final int size = mSessions.size();
for (int i = 0; i < size; i++) {
// 创建 PackageInstallerSession 对象
final PackageInstallerSession session = mSessions.valueAt(i);
// 通过 session 写入
session.write(out, mSessionsDir);
}
out.endTag(null, TAG_SESSIONS);
out.endDocument();
mSessionsFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
mSessionsFile.failWrite(fos);
}
}
}
安装应用的开端
- 在 android 中,通过发送 Intent 就可以启动安装应用流程。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
context.startActivity(intent);
- 在 android 系统应用 PackageInstaller 中有一个 PackageInstallerActivity 会响应这个 Intent。在这个 Activity 中有两个很重要的成员变量 PackageManager mPm; 和 PackageInstaller mInstaller; 分别是 ApplicationPackageManager 和 PackageInstaller 的实例对象。这两个对象也是 PackageManagerService 和 PackageInstallerService 的代理对象。创建这两个对象的方法如下:
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(null);
mPm = getPackageManager();
mInstaller = mPm.getPackageInstaller();
}
- 点击确认安装按钮后会执行 startInstall()
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);
finish();
}
- 上面的代码跳转到了 InstallInstalling.class ,它也是一个 Activity
首先看它的 onCreate() 方法,主要是创建了 sessionId,其中取消按钮的点击事件mInstallingTask ,是在 onResume() 中创建的,所以接下来后看一下 onResume 的代码。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.install_installing);
ApplicationInfo appInfo = getIntent()
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = getIntent().getData();
if ("package".equals(mPackageURI.getScheme())) {
try {
// 如果是 package 直接调用 installExistingPackage
// installExistingPackage 会调用到 PMS 的 mPm.installExistingPackageAsUser()
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
// 如果是 file
final File sourceFile = new File(mPackageURI.getPath());
PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo,
sourceFile), R.id.app_snippet);
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);
// Reregister for result; might instantly call back if result was delivered while
// activity was destroyed
try {
InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
// Does not happen
}
} else {
// 获取参数
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.installFlags = PackageManager.INSTALL_FULL_APP;
params.referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
params.originatingUri = getIntent()
.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
UID_UNKNOWN);
params.installerPackageName =
getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
File file = new File(mPackageURI.getPath());
try {
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
params.setAppPackageName(pkg.packageName);
params.setInstallLocation(pkg.installLocation);
params.setSize(
PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
} catch (PackageParser.PackageParserException e) {
Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only apk size.");
params.setSize(file.length());
} catch (IOException e) {
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only apk size.");
params.setSize(file.length());
}
try {
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
try {
// 创建 SessionId 这是安装的唯一id 存储到 mSessions集合中,如果安装失败还可以通过id 继续之前未完成的安装
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
}
mCancelButton = (Button) findViewById(R.id.cancel_button);
mCancelButton.setOnClickListener(view -> {
// mInstallingTask 是在 onResume() 中创建的,所以下面会看一下 onResume() 的代码,看看task执行的是谁什么内容
if (mInstallingTask != null) {
mInstallingTask.cancel(true);
}
if (mSessionId > 0) {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
mSessionId = 0;
}
setResult(RESULT_CANCELED);
finish();
});
mSessionCallback = new InstallSessionCallback();
}
}
- InstallInstalling.class 的 onResume()
@Override
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
// getPackageInstaller() 返回的是 PackageInstallerService
PackageInstaller installer = getPackageManager().getPackageInstaller();
// 通过唯一id mSessionId 获取安装信息 ;onCreate 中创建的mSessionId 存储到了installer 的 mSessions数组中
// 通过 getSessionInfo 获取信息如果获取不到就直接cancel了
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
if (sessionInfo != null && !sessionInfo.isActive()) {
// 创建 InstallingAsyncTask
mInstallingTask = new InstallingAsyncTask();
// 执行 mInstallingTask
mInstallingTask.execute();
} else {
// we will receive a broadcast when the install is finished
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
}
}
onResume() 方法中,继续下一步安装是执行了 InstallingAsyncTask.execute() 接下来看一下这个 task;
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
// 通过 openSession() 获取保存的 session信息 如果获取不到安装结束
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
return null;
}
session.setStagingProgress(0);
try {
// 将file信息 通过流写入到 PackageInstaller.Session session; 中
File file = new File(mPackageURI.getPath());
try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
session.fsync(out);
break;
}
if (isCancelled()) {
session.close();
break;
}
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
session.addProgress(fraction);
}
}
}
}
return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);
session.close();
return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(
getPackageManager().getPermissionControllerPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 这句是重点会调用到 PackageInstallerSession 的 commit方法
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
- 上一步的 task 会调用到 PackageInstallerSession 的 commit 方法
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
final boolean wasSealed;
synchronized (mLock) {
// 。。。。
mActiveCount.incrementAndGet();
mCommitted = true;
// 最后发送了 handler 信息
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
- 接收 MSG_COMMIT 的 handler 方法
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);
}
}
break;
// .....
}
return true;
}
};
commitLocked 方法最后调用了下面这句话
private final PackageManagerService mPm;
private void commitLocked() throws PackageManagerException {
// ...
mPm.installStage(mPackageName, stageDir, localObserver, params,
mInstallerPackageName, mInstallerUid, user, mSigningDetails);
}
安装逻辑就走到了 PackageManagerService 的 installStage() 方法,后面的安装就和 PMS有关了
应用安装的第一阶段-复制文件
- 接下来继续从 installStage() 方法开始
void installStage(String packageName, File stagedDir,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
PackageParser.SigningDetails signingDetails) {
// ...
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, signingDetails, installReason);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
// mHandler 发送了 INIT_COPY 信息 携带了安装的参数 InstallParams
mHandler.sendMessage(msg);
}
- mHandler 接收的消息
case INIT_COPY: {
// 获取参数
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (!mBound) {
// connectToService 连接成功会把 mBound 设置成 true
// 绑定 service 成功后也会发送 mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();
return;
} else {
// 绑定服务成功把安装信息保存到 mPendingInstalls
// 待收到连接信息返回后继续安装
mPendingInstalls.add(idx, params);
}
} else {
// 之后再接收到信息就直接添加到 mPendingInstalls
mPendingInstalls.add(idx, params);
// Already bound to the service. Just make
// sure we trigger off processing the first request.
if (idx == 0) {
// mPendingInstalls 如果只有一个则立刻发出 MCS_BOUND 消息
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
- 接下来看 handler 收到了 MCS_BOUND 消息后是怎么处理的;
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
// 如果 mContainerService == null 是异常情况
if (mContainerService == null) {
if (!mBound) {
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
// 通知回调者出错了
params.serviceError();
}
mPendingInstalls.clear();
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
// 上一步添加到了 mPendingInstalls 中,判断如果有数据
// 取出安装数据
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
// 执行安装操作
if (params.startCopy()) {
// We are done... look for more work or to go idle.
// Delete pending install
// 工作完成删除列表第一项
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
// 判断是否还有未完成的任务 size == 0 代表没有未完成的任务
if (mPendingInstalls.size() == 0) {
// mBound 是在连接service的时候设置的true 如果false说明service未绑定
if (mBound) {
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// 如果没有安装信息并且 sergice 已经绑定,延迟发送一个解绑信息
sendMessageDelayed(ubmsg, 10000);
}
} else {
// 如果还有未完成的任务,则再次发送 MCS_BOUND ,取出头信息继续startCopy() 操作
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
}
} else {
// 代表没有要执行的任务 也就是 mPendingInstalls 队列中没有数据
}
break;
}
- 接下来看 params.startCopy() 是如何操作的
final boolean startCopy() {
boolean res;
try {
// private static final int MAX_RETRIES = 4;
// 如果重试 4 次还未成功则退出
if (++mRetries > MAX_RETRIES) {
// 发送 MCS_GIVE_UP 消息
mHandler.sendEmptyMessage(MCS_GIVE_UP);
handleServiceError();
return false;
} else {
// 执行安装 startCopy() 方法也会捕获 handleStartCopy 内部抛出的异常 进行重连等操作
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
// 安装出错 发送消息重新连接
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
handleReturnCode();
return res;
}
startCopy() 将会调用 handleStartCopy(); 来完成安装操作。startCopy() 主要是进行错误处理,捕获到 handleStartCopy 抛出异常以后,将会发送 MCS_RECONNECT 消息进行重新绑定 service,绑定成功会重新安装流程,startCopy() 将会再次调用,重试次数超过4次将安装失败。如果成功将会调用 handleReturnCode();继续处理。
- handleStartCopy() 方法
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
if (origin.staged) {
if (origin.file != null) {
// 记录安装位置的标志
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
// 是否安装在 sd 卡
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
// 是否安装在内部
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
// 表示轻量级的临时安装包
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
// 标记冲突:如果既安装到sd卡 又安装到内部 则安装失败 记录错误类型
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 {
// 获取关于安装包信息的 PackageInfoLite 对象
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
packageAbiOverride);
// 下面这一段:如果安装空间不够 释放cache空间
if (!origin.staged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// TODO: focus freeing disk space on the target device
final StorageManager storage = StorageManager.from(mContext);
final long lowThreshold = storage.getStorageLowBytes(
Environment.getDataDirectory());
final long sizeBytes = mContainerService.calculateInstalledSize(
origin.resolvedPath, 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);
}
/*
* 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;
}
}
}
// ....
// ....
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.
*/
// 下面很长一段作用是应用的校验,做法是通过发送有校验功能的 intent 进行。
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
// ... 省略代码
/*
* We don't want the copy to proceed until verification
* succeeds, so null out this field.
*/
mArgs = null;
}
} else {
// 如果没有校验 则直接调用 copyApk 继续处理
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
handleStartCopy() 的逻辑是先通过 getMinimalPackageInfo() 确定安装空间是否足够,并记录错误原因,如果安装空间不够则通过 mInstaller.freeCache() 释放空间。接下来调用 final InstallArgs args = createInstallArgs(this); 创建 InstallArgs 对象(InstallArgs 分为 AsecInstallArgs 和 FileInstallArgs)。接下来是很长一段应用的校验,然后调用args.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);
}
}
copyApk 调用了 doCopyApk() 代码如下:
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
// 在 data/app 生成临时文件
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
// 为临时文件创建文件描述符,它可以通过 Binder 传递
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
@Override
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid filename: " + name);
}
try {
final File file = new File(codeFile, name);
final FileDescriptor fd = Os.open(file.getAbsolutePath(),
O_RDWR | O_CREAT, 0644);
// 0644->即用户具有读写权限,组用户和其它用户具有只读权限;
Os.chmod(file.getAbsolutePath(), 0644);
return new ParcelFileDescriptor(fd);
} catch (ErrnoException e) {
throw new RemoteException("Failed to open: " + e.getMessage());
}
}
};
int ret = PackageManager.INSTALL_SUCCEEDED;
// 使用 DefaultContainerService 的 copyPackage 方法复制文件
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
// 安装应用自带native的动态库
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
abiOverride);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
doCopyApk() 是调用了 DefaultContainerService 的 copyPackage() 方法复制文件到 /data/app 下,如果应用中还有动态库也会把 apk的动态库提取出来。
执行完这一步后 应用安装的第一步就结束了,应用被安装到了 /data/app 下。
第二阶段-装载应用
-
接下来是第二阶段的工作,把应用的格式转换成 ota 的格式,为应用创建数据目录,最后把应用的信息装载到 PackageManagerService 的数据结构中。
-
前面最后走到了 doCopyApk() 方法,前面的调用连可以发现,startCopy 再走完copy 流程之后会调用 handleReturnCode(); 方法。
-
handleReturnCode();
@Override
void handleReturnCode() {
if (mArgs != null) {
// 调用了 processPendingInstall 继续处理
processPendingInstall(mArgs, mRet);
}
}
- processPendingInstall() 方法
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
// 防止重复调用
mHandler.removeCallbacks(this);
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
res.removedInfo = null;
// 判断是否安装成功
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// 如果安装成功
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
// 装载安装的应用
installPackageTracedLI(args, res);
}
args.doPostInstall(res.returnCode, res.uid);
}
// 下面一段是执行备份
// ....
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 消息
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
});
}
processPendingInstall() 方法中发送了一个 mHandler.post 异步消息,这样过程将以异步的方式执行,调用了 installPackageTracedLI(args, res); 来装载应用,然后执行了备份,最后发送了 POST_INSTALL 来继续处理。
- installPackageTracedLI 方法
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
final int installFlags = args.installFlags;
final String installerPackageName = args.installerPackageName;
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;
@ScanFlags 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 = installerPackageNa
// Sanity check
if (instantApp && (forwardLocked || onExternal)) {
res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
return;
}
// Retrieve PackageSettings and parse package
// 创建 apk 文件解析器
@ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 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 文件
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Instant apps have several additional install-time checks.
if (instantApp) {
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must target at least O");
return;
}
if (pkg.applicationInfo.targetSandboxVersion != 2) {
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must use targetSandboxVersion 2");
return;
}
if (pkg.mSharedUserId != null) {
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package may not declare a sharedUserId");
return;
}
}
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static shared libraries have synthetic package names
renameStaticSharedLibraryPackage(pkg);
// No static shared libs on external storage
if (onExternal) {
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
// 如果是安装集群包 则把子包的信息也解析存储
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;
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.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
pkg.setSigningDetails(args.signingDetails);
} else {
PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
}
if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
< SignatureSchemeVersion.SIGNING_BLOCK_V2) {
Slog.w(TAG, "Instant app package " + pkg.packageName
+ " is not signed with at least APK Signature Scheme v2");
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must be signed with APK Signature Scheme v2 or greater");
return;
}
// Get rid of all references to package scan path via parser.
pp = null;
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
// 判断是否是更新应用
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; // true 代表替换升级应用
} else if (mPackages.containsKey(pkgName)) {
// true 代表替换升级应用
replace = true;
}
// Child packages are installed through the parent package
if (pkg.parentPackage != null) {
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;
if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
&& newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
return;
}
// Prevent persistent apps from being updated
if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) {
return;
}
// Prevent installing of child packages
if (oldPackage.parentPackage != null) {
return;
}
}
}
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
if (libraryEntry != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
}
}
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
return;
}
} else {
try {
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
// We don't care about disabledPkgSetting on install for now.
final boolean compatMatch = verifySignatures(
signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPackages) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
}
} 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);
}
// 检查应用中的 permission 是否已经被其他应用定义了
// 如果重新定义的系统应用定义的 permission 则忽略本应用的定义 然后继续
// 如果定义的是非系统应用定义的 permission 则本地安装失败
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
final PackageParser.Permission perm = pkg.permissions.get(i);
final BasePermission bp =
(BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
// Don't allow anyone but the system to define ephemeral permissions.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
&& !systemApp) {
Slog.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;
final String sourcePackageName = bp.getSourcePackageName();
final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (sourcePackageName.equals(pkg.packageName)
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else {
// in the event of signing certificate rotation, we need to see if the
// package's certificate has rotated from the current one, or if it is an
// older certificate with which the current is ok with sharing permissions
if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
pkg.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
sigsOk = true;
} else if (pkg.mSigningDetails.checkCapability(
sourcePackageSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
// the scanned package checks out, has signing certificate rotation
// history, and is newer; bring it over
sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
sigsOk = true;
} else {
sigsOk = false;
}
}
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 (!sourcePackageName.equals("android")) {
res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ pkg.packageName + " attempting to redeclare permission "
+ perm.info.name + " already owned by " + sourcePackageName);
res.origPermission = perm.info.name;
res.origPackage = sourcePackageName;
return;
} else {
Slog.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()) {
Slog.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.getProtectionLevel();
}
}
}
}
}
}
if (systemApp) {
if (onExternal) {
// 系统应用不允许安装在 sd 卡上
// 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;
}
}
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()) {
// 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, abiOverride, extractNativeLibs);
} catch (PackageManagerException pme) {
Slog.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);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
}
}
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}
if (PackageManagerServiceUtils.isApkVerityEnabled()) {
String apkPath = null;
synchronized (mPackages) {=
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null && ps.isPrivileged()) {
apkPath = pkg.baseCodePath;
}
}
if (apkPath != null) {
final VerityUtils.SetupResult result =
VerityUtils.generateApkVeritySetupData(apkPath);
if (result.isOk()) {
FileDescriptor fd = result.getUnownedFileDescriptor();
try {
final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath);
mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
} catch (InstallerException | IOException | DigestException |
NoSuchAlgorithmException e) {
return;
} finally {
IoUtils.closeQuietly(fd);
}
} else if (result.isFailed()) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Failed to generate verity");
return;
} else {
}
}
}
if (!instantApp) {
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
} else {
}
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {
// 如果安装的是升级包 调用 replacePackageLIF 继续处理
if (pkg.applicationInfo.isStaticSharedLibrary()) {
PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
if (existingPkg != null &&
existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
+ "static-shared libs cannot be updated");
return;
}
}
replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
installerPackageName, res, args.installReason);
} else {
// 如果是新应用 调用 installNewPackageLIF 继续处理
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
方法中解析了应用包,然后判断是升级应用调用了 replacePackageLIF() 还是新的应用 调用了 installNewPackageLIF()
下面看一下装载后发送的 POST_INSTALL 是怎么处理的
case POST_INSTALL: {
PostInstallData data = mRunningInstalls.get(msg.arg1);
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
if (data != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
final boolean grantPermissions = (args.installFlags
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
final boolean killApp = (args.installFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
final boolean virtualPreload = ((args.installFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
final String[] grantedPermissions = args.installGrantPermissions;
// Handle the parent package
// 调用了 handlePackagePostInstall 内部会判断是否安装成功,发送对应的 广播事件
// 通知其他应用进行处理 比如桌面添加图标等,并回调给安装者成功事件
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);
}
}
} break;