研究应用的安装过程,老样子,咱们仍是先从使用入手。java
在Android
中,经过发送Intent
就能够启动应用的安装过程,好比:android
Uri uri = Uri.fromFile(new File(apkFilePath));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri,"application/vnd.android.package-archive");
startActivity(intent);
复制代码
而在Android
的系统应用PackageInstaller
中有一个InstallStart
会响应这个Intent
,数组
<activity android:name=".InstallStart" android:theme="@style/Installer" android:exported="true" android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
......
</activity>
复制代码
在InstallStart
中会进行各类Uri
的判断,最终会跳转到一个叫作PackageInstallerActivity
的界面。markdown
国内的厂商基本上会在
InstallStart
这里进行修改,替换为本身的安装界面session
对于PackageInstallerActivity
来讲,它的主要做用是数据结构
Uri
协议进行解析,包括file
和package
两种
file
协议会解析APK
文件获得包信息PackageInfo
Intent
判断得出该APK
不是未知来源,就会初始化安装确认界面Dialog
或者跳转到设置界面当点击确认安装后,其实会执行到startInstall()
方法,相关内容以下:并发
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
......
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
......
startActivity(newIntent);
finish();
}
复制代码
上面的逻辑是跳转到InstallInstalling
界面进行安装,咱们看看这个Activity
:app
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
......
if ("package".equals(mPackageURI.getScheme())) {
// 直接安装 package
try {
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
// 对于 file 安装,按照session的逻辑去走
// 这部分在onResume中开始
final File sourceFile = new File(mPackageURI.getPath());
......
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);
......
} else {
......
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
......
// 建立应用安装状态的Observer
// 真正注册是在后面 Session 的 commitLocked 中
// InstallEventReceiver 这里是作了二次封装,方便进行持久化操做
InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult);
}
......
}
}
@Override
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
// 启动异步安装任务 InstallingAsyncTask 进行一系列的session操做
if (sessionInfo != null && !sessionInfo.isActive()) {
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
}
......
}
}
复制代码
从上面的方法咱们能够看到安装操做主要分为两个接口:异步
getPackageManager().installExistingPackage()
:主要是对已经并扫描到Settings
的mPackages
集合中的应用进行操做
userID
从集合中查询应用状态,若是存在而且应用没有安装,就进行一些简单的配置工做prepareAppDataAfterInstallLIF
方法,建立特定userID
下的应用数据InstallingAsyncTask
任务中的Session
系列操做:一个应用完整的安装过程从这里开始 private final class InstallingAsyncTask extends AsyncTask<Void, Void, PackageInstaller.Session> {
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
......
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
try {
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) {
......
out.write(buffer, 0, numRead);
......
}
}
}
return session;
}
......
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
......
session.commit(pendingIntent.getIntentSender());
......
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
......
}
}
复制代码
APK
的Uri
,将APK
的信息经过IO
流的形式写入到PackageInstaller.Session
中PackageInstallerSession.commit()
函数session
这个东西看来很重要,那么咱们先来看看PackageInstallerSession
吧async
PackageInstallerSession
Android
经过PackageInstallerSession
来表示一次安装过程,一个PackageInstallerSession
包含一个系统中惟一的一个SessionId
,若是一个应用的安装必须分几个阶段来完成,即便设备重启了,也能够经过这个ID
来继续安装过程
PackageInstallerSession
中保存了应用安装的相关数据,例如,安装包的路径、安装的进度、中间数据保存的目录等。
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
,能够经过接口openSession()
打开它。openSession()
方法的代码以下所示:
@Override
public IPackageInstallerSession openSession(int sessionId) {
try {
return openSessionInternal(sessionId);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
}
复制代码
openSession()
方法将返回一个IPackageInstallerSession
对象,它是Binder
服务PackageInstallerSession
的IBinder
对象。在PackageInstallerService
中mSessions
数组保存了全部PackageInstallerSession
对象,定义以下:
@GuardedBy("mSessions")
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
复制代码
咱们知道,当PackageManagerService
初始化时会建立PackageInstallerService
服务,在这个服务的初始化函数中会读取/data/system
目录下的install_sessions.xml
文件,这个文件中保存了系统中未完成的Install Session
。而后PackageInstallerService
会根据文件的内容建立PackageInstallerSession
对象并插入到mSessions
中。
而对于上面提到的commit()
函数,是真正触发PMS
安装的函数,定义以下:
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
......
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) {
......
commitLocked();
......
}
break;
......
}
return true;
}
};
private void commitLocked() throws PackageManagerException {
......
mRemoteObserver.onUserActionRequired(intent);
......
mPm.installStage(mPackageName, stageDir, localObserver, params,
mInstallerPackageName, mInstallerUid, user, mSigningDetails);
}
复制代码
commit()
函数最后会调用到PMS
的installStage()
方法,到这里就触发了安装的第一阶段:文件复制
咱们已经知道PackageInstallerSession
经过调用PMS
的installStage()
方法开启了安装第一阶段,不过整个安装过程比较复杂,咱们先看看这个过程的序列图:
installStage()
咱们继续从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 InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
sessionParams.grantedRuntimePermissions, signingDetails, installReason);
......
msg.obj = params;
......
mHandler.sendMessage(msg);
}
复制代码
installStage()
方法主要进行了:
InstallParams
对象
InstallParams
是安装过程当中的主要数据结构Android
把安装过程拆分,把调用过程的参数数据保存到InstallParams
中Message
消息
msg.what
为INIT_COPY
msg.obj
为InstallParams
对象先来简单了解下InstallParams
的类:
上图中的类都是PMS的内部类
InstallParams
继承自HandlerParams
,用来记录安装应用的参数。InstallParams
中有一个成员变量mArgs
,是一个抽象类型InstallArgs
,主要是用来执行APK
的复制,真正的实现类包括:
FileInstallArgs
:用来完成非ASEC
应用的安装
asec
全称是Android Secure External Cache
MoveInstallArgs
:用来完成已安装应用的移动安装简单了解完InstallParams
,咱们继续看INIT_COPY
消息的处理过程:
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
......
if (!mBound) {
// 绑定 DefaultContainerService
if (!connectToService()) {
params.serviceError();
......
return;
} else {
// 链接成功,将安装信息保存到 mPendingInstalls 的尾部
mPendingInstalls.add(idx, params);
}
} else {
// 若是已经绑定服务,直接插入到集合尾部
mPendingInstalls.add(idx, params);
if (idx == 0) {
// 若是插入前的集合为空
// 直接发送 MCS_BOUND 消息
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
复制代码
整个过程比较简洁:
connectToService()
去绑定和启动DefaultContainerService
服务。
onServiceConnected()
返回DefaultContainerConnection
中能够看到,当服务链接成功后,会发送MSC_BOUNF
消息class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
final IMediaContainerService imcs = IMediaContainerService.Stub
.asInterface(Binder.allowBlocking(service));
mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
}
}
复制代码
mPendingInstalls
列表中。
mPendingInstalls
进行排队MSC_BOUND
消息那么,重点又转移到了MCS_BOUND
的消息处理,代码以下:
case MCS_BOUND: {
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mContainerService == null) {
if (!mBound) {
// DefaultContainerService bind失败的状况
for (HandlerParams params : mPendingInstalls) {
params.serviceError();
......
}
mPendingInstalls.clear();
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
// 取出头部安装参数
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
......
if (params.startCopy()) {// 执行安装
// 已执行成功,移除头部元素
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
......
// 若是集合中没有须要安装的信息了,发送MCS_UNBIND延时消息进行解绑
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
sendMessageDelayed(ubmsg, 10000);
}
} else {
// 若是集合中还存在安装信息,发送 MCS_BOUND 消息,继续处理
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
}
}
break;
}
复制代码
MCS_BOUND
消息的处理过程就是:
InstallParams
类的startCopy()
方法来执行安装
mPendingInstalls
中还有安装信息,就会重复发送MCS_BOUND
消息10s
的MCS_UNBIND
消息
MCS_UNBIND
消息的处理很简单,收到消息后若是发现mPendingInstalls
中有数据了,则发送MCS_BOUND
消息继续安装。DefaultContainerService
链接,安装过程到此结束case MCS_UNBIND: {
if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
if (mBound) {
// 断开 DefaultContainerService 链接
disconnectService();
}
} else if (mPendingInstalls.size() > 0) {
// 继续发送执行安装操做的消息
mHandler.sendEmptyMessage(MCS_BOUND);
}
break;
}
复制代码
针对startCopy()
方法的处理过程,代码以下:
private static final int MAX_RETRIES = 4;
final boolean startCopy() {
boolean res;
try {
// 重试超过4次,则推出
if (++mRetries > MAX_RETRIES) {
// 发送 MCS_GIVE_UP 消息取消安装
mHandler.sendEmptyMessage(MCS_GIVE_UP);
handleServiceError();
return false;
} else {
// 核心方法,执行 copy
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
// 出现异常,发送 MCS_RECONNECT 消息,进行重连
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
// 开始进入第二阶段
handleReturnCode();
return res;
}
复制代码
startCopy()
方法经过调用handleStartCopy()
来完成安装过程。考虑到安装过程的不肯定性,startCopy()
主要是进行错误处理:
MCS_RECONNECT
消息处理中,会从新绑定DefaultContainerService
startCopy()
会被再次调用。mRetries
中,超过4次,安装失败handleStartCopy()
执行成功,startCopy()
会调用handleReturnCode()
来继续处理handleStartCopy()
方法比较长,简要代码以下:
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
......
if (onInt && onSd) {
// 设置安装路径异常标志
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (onSd && ephemeral) {
// 设置安装路径异常标志
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
// 获取安装包中的 PackageInfoLite 对象
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride);
......
if (!origin.staged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// TODO: focus freeing disk space on the target device
// 若是安装空间不够,尝试释放cache空间
......
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
......
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
......
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
}
......
final InstallArgs args = createInstallArgs(this);
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
......
if (!origin.existing && requiredUid != -1 && isVerificationEnabled(verifierUser.getIdentifier(), installFlags, installerUid)) {
// 此部分是在执行应用的校验
// 主要经过向待校验功能的组件发送Intent来完成
......
/* * We don't want the copy to proceed until verification * succeeds, so null out this field. */
mArgs = null;
} else {
// 无需校验,调用 InstallArgs 的 copyAPK 方法继续处理
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
复制代码
上面handleStartCopy()
方法的主要逻辑是:
getMinimalPackageInfo()
方法确认是否还有足够的安装空间,若是安装空间不够,会经过mInstaller.freeCache()
来释放一部分createInstallArgs()
建立InstallArgs
对象,createInstallArgs()
方法中会对InstallParams
的move
成员变量进行判断
move
不为空使用MoveInstallArgs
move
为空使用FileInstallArgs
,咱们重点来看这个apk
进行校验,这个校验过程是经过发送Intent.ACTION_PACKAGE_NEEDS_VERIFICATION)
广播给系统中全部能够接收该Intent
的应用来完成的InstallArgs
的copyApk()
方法InstallArgs
的copyApk()
方法以下:
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
......
return doCopyApk(imcs, temp);
}
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
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;
}
// 为临时文件建立文件描述符 ParcelFileDescriptor
// 主要是为了将文件序列化,方便经过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);
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;
}
复制代码
copyApk()
最后调用了DefaultContainerService
的copyPackage()
方法将应用的文件复制到了/data/app
目录下。若是应用中还有native
的动态库,也会把apk中的库文件提取出来。
执行完copyApk()
方法后,安装第一阶段的工做就完成了,应用安装到了/data/app
目录下。咱们接下来看看handleReturnCode()
的内容,也就是第二阶段。
第二阶段的工做主要是
oat
格式PMS
的数据结构中handleReturnCode()
方法代码以下:
void handleReturnCode() {
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
复制代码
handleReturnCode()
只是调用了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);// 防止重复调用
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);
}
......
// 将相关数据记录到 mRunningInstalls 集合中
PostInstallData data = new PostInstallData(args, res);
mRunningInstalls.put(token, data);
...... // 省略备份部分
if (!doRestore) {
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
});
}
复制代码
processPendingInstall()
方法中post
了一个任务:
installPackageTracedLI()
来装载应用IBackupManager
服务执行备份相关的操做,这部分就不先深刻了,篇幅已通过大。。。POST_INSTALL
消息继续处理咱们仍是先看下核心方法installPackageTracedLI()
的内容,代码以下:
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
installPackageLI(args, res);
}
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
......
// Result object to be returned
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
res.installerPackageName = installerPackageName;
......
// 建立 APK 解析对象 PackageParser
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
......
final PackageParser.Package pkg;
try {
// 解析 APK
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
}
......
// 收集应用的签名信息
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
pkg.setSigningDetails(args.signingDetails);
} else {
PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
......
pp = null;
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
// Check if installing already existing package
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;
}
......// 省略部分新旧应用的属性比对
}
// 检查已安装的应用集合中是否存在该应用的记录
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
// 存在同名应用
......// 省略一些本地库的签名判断
// 检查是否为系统应用
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是否被重复定义
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);
......
// 省略部分只要是对系统定义权限和非系统定义权限的区分
// 若是是系统应用定义的权限,则忽略本应用中的定义,而后继续
// 若是是非系统应用定义的权限,则本次安装失败
......
}
}
......
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {
......
replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
installerPackageName, res, args.installReason);
} else {
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
...... // 省略 dexopt 相关操做
}
}
复制代码
这部分的代码逻辑和前面介绍的scanDirLI()
很像,不详细介绍了,总体流程是:
PackageParser
解析了安装的应用文件
scanDirLI()
中的parsePackage()
同样replacePackageLIF()
继续处理installNewPackageLIF()
处理这里不深刻进行分析了哈,跟踪完调用过程后其实都会走到addForInitLI()
中
再次吐槽一下
PMS
,package
解析部分的调用是真滴复杂啊,各类条件判断
咱们继续看下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;
......
// 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);
}
......
}
......
} break;
复制代码
POST_INSTALL
的消息处理基本上都是在执行handlePackagePostInstall()
方法,handlePackagePostInstall()
方法主要工做包括两个:
Intent.ACTION_PACKAGE_ADDED
:新应用安装成功Intent.ACTION_PACKAGE_REPLACED
:应用更新成功APK
安装完成。例如,Launcher
中须要增长应用的图标等IPackageInstallObserver2
的onPackageInstalled()
方法通知观察者
PackageInstaller
在安装应用时就是经过注册观察者来实现结果监听的关于
PMS
的软件卸载流程,你们一样能够从PackageInstaller
入手,关键类是UninstallUninstalling
。这里就先跳过了,PMS
篇幅占用时间过久了。。。。。