包指的是Apk、jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一个机制来进行包的加载、解析、管理等操作,这就是包管理机制。包管理机制由许多类一起组成,其中核心为PackageManagerService
(PMS
),它负责对包进行管理。
PackageManager
是一个抽象类,具体实现类为ApplicationPackageManager
,ApplicationPackageManager
中的方法会通过IPackageManager
与PMS
进行进程间通信,因此PackageManager
所提供的功能最终是由PMS
来实现的。
Package Manager
的功能主要包含以下部分:
ApplicationInfo
)Activity
、Provider
、Receiver
、Service
四大组件的信息Permission
和Permission Group
信息的增加、删除、查询和检查UID
、GID
、包名、系统默认程序等信息APK的安装场景主要有以下几种:
adb push/install
packageinstaller
安装该Apk。最终都交由PMS
来进行处理。
代码参考AOSP 中 API 23
(android 6.0.1)
packageinstaller
: http://androidxref.com/6.0.1_r10/xref/packages/apps/PackageInstaller/
它的AndroidManifest.xml
显示入口为PackageInstallerActivity
,
<activity android:name=".PackageInstallerActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true">
当我们调用PackageInstaller
来安装应用时会跳转到PackageInstallerActivity
,并调用PackageInstallerActivity
的onCreate
方法, 这个方法部分功能为:
Intent
获取相关数据package协议
和file协议
的Uri进行处理,得到包信息PackageInfo
initiateInstall
安装,未知来源弹框提示)protected void onCreate(Bundle icicle) {
...
// 1.从Intent获取相关数据
final Intent intent = getIntent();
if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
....
mSessionId = sessionId;
mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath));
mOriginatingURI = null;
mReferrerURI = null;
} else {
mSessionId = -1;
mPackageURI = intent.getData();
mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
}
...
final boolean unknownSourcesAllowedByAdmin = isUnknownSourcesAllowedByAdmin();
final boolean unknownSourcesAllowedByUser = isUnknownSourcesEnabled();
// 是否为未知来源的APK
boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
...
// 2.分别对package协议和file协议的Uri进行处理,得到包信息PackageInfo
final PackageUtil.AppSnippet as;
if ("package".equals(mPackageURI.getScheme())) { // package协议
mInstallFlowAnalytics.setFileUri(false);
mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);
....
} else { // file协议
mInstallFlowAnalytics.setFileUri(true);
final File sourceFile = new File(mPackageURI.getPath());
PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
....
mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
PackageManager.GET_PERMISSIONS, 0, 0, null,
new PackageUserState());
...
}
mInstallFlowAnalytics.setPackageInfoObtained();
...
// 3.对不同来源Apk进行处理
if (!requestFromUnknownSource) { // 已知来源的Apk直接安装
initiateInstall();
return;
}
....
final boolean isManagedProfile = mUserManager.isManagedProfile();
if (!unknownSourcesAllowedByAdmin
|| (!unknownSourcesAllowedByUser && isManagedProfile)) { // 禁止安装,就弹出提示Dialog
showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
mInstallFlowAnalytics.setFlowFinished(
InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
} else if (!unknownSourcesAllowedByUser) { // 弹出询问框
// Ask user to enable setting first
showDialogInner(DLG_UNKNOWN_SOURCES);
mInstallFlowAnalytics.setFlowFinished(
InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
} else { // 允许安装未知来源的APK
initiateInstall();
}
===>可以看到接着是调用了initiateInstall
方法, 这个方法部分功能为:
startInstallConfirm
初始化安装确认界面代码如下:
private void initiateInstall() {
String pkgName = mPkgInfo.packageName; //1.得到包名
// 检查设备上是否已有包含此名称的包,但它已被重命名为其他内容
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// 2.根据包名获取应用程序信息
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
mAppInfo = null;
}
mInstallFlowAnalytics.setReplace(mAppInfo != null);
mInstallFlowAnalytics.setSystemApp(
(mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));
// 3. 初始化安装确认界面
startInstallConfirm();
}
===>startInstallConfirm
初始化并显示安装确认界面,就是我们平常安装APK时出现的界面,界面上有确认和取消按钮,并列出了安装该APK需要访问的系统权限,这个方法部分功能为:
代码如下:
private void startInstallConfirm() {
// 1.初始化界面相关代码
...
// 2.列出安装该APK需要访问的系统权限,并显示
AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
final int N = perms.getPermissionCount(AppSecurityPermissions.WHICH_ALL);
if (mAppInfo != null) {
msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_question_update_system
: R.string.install_confirm_question_update;
mScrollView = new CaffeinatedScrollView(this);
mScrollView.setFillViewport(true);
boolean newPermissionsFound = false;
if (!supportsRuntimePermissions) {
newPermissionsFound =
(perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound);
if (newPermissionsFound) {
permVisible = true;
mScrollView.addView(perms.getPermissionsView(
AppSecurityPermissions.WHICH_NEW));
}
}
....
} else {
findViewById(R.id.tabscontainer).setVisibility(View.GONE);
findViewById(R.id.divider).setVisibility(View.VISIBLE);
}
....
mInstallFlowAnalytics.setPermissionsDisplayed(permVisible);
....
mInstallConfirm.setVisibility(View.VISIBLE);
mOk = (Button)findViewById(R.id.ok_button);
mCancel = (Button)findViewById(R.id.cancel_button);
mOk.setOnClickListener(this); // 3.绑定安装按钮事件
mCancel.setOnClickListener(this);
if (mScrollView == null) {
// There is nothing to scroll view, so the ok button is immediately
// set to install.
mOk.setText(R.string.install);
mOkCanInstall = true;
} else {
mScrollView.setFullScrollAction(new Runnable() {
@Override
public void run() {
mOk.setText(R.string.install); // 安装按钮
mOkCanInstall = true;
}
});
}
}
简单总结下PackageInstaller
初始化:
package协议
和file协议
的Uri进行处理,得到mPkgInfo
initiateInstall
安装,未知来源弹框提示)Intent
判断得出该APK不是未知来源,就会初始化安装确认界面用户点击安装确认界面的mOk
按钮,就会触发PackageInstallerActivity
的onClick
方法,内部调用了startInstall
方法,如下所示:
public void onClick(View v) {
if (v == mOk) {
if (mOkCanInstall || mScrollView == null) {
mInstallFlowAnalytics.setInstallButtonClicked();
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);
mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult(
PackageManager.INSTALL_SUCCEEDED);
finish();
} else {
startInstall(); // 安装函数
}
} else {
mScrollView.pageScroll(View.FOCUS_DOWN);
}
} else if(v == mCancel) {
...
}
}
===>startInstall
启动了一个新的InstallAppProgress
activity, 并把一些参数传了过去,代码如下:
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, InstallAppProgress.class);
// 省略传入部分参数代码
....
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);
finish();
}
===>InstallAppProgress
类的onCreate
函数先取得传入参数,再调用initView
方法,代码如下:
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// 省略传入部分参数代码
...
initView();
}
===>InstallAppProgress
类的initView
方法,代码如下:
public void initView() {
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (NameNotFoundException e) {
}
if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
}
....
if ("package".equals(mPackageURI.getScheme())) { // package协议
try {
pm.installExistingPackage(mAppInfo.packageName);
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_SUCCEEDED);
} catch (PackageManager.NameNotFoundException e) {
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_FAILED_INVALID_APK);
}
} else {
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
installerPackageName, verificationParams, null);
}
}
===>精简了一下,主要是这两个方法:
pm.installExistingPackage
,实际上调用的就是ApplicationPackageManager
的installExistingPackage
,它是为其他用户安装已安装过的apkpm.installPackageWithVerificationAndEncryption
,实际上调用的就是ApplicationPackageManager
的installPackageWithVerificationAndEncryption
,它是安装一个apk这里我们只跟踪ApplicationPackageManager
的installPackageWithVerificationAndEncryption
, 最终内部是调用了 mPM.installPackage
, 代码如下:
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, verificationParams, encryptionParams);
}
--->installCommon方法的实现如下:
private void installCommon(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
...
final String originPath = packageURI.getPath();
try {
mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
verificationParams, null);
} catch (RemoteException ignored) {
}
}
===> mPM
的定义为IPackageManager
,也就是IPackageManager.aidl
,很明显,它最终是调到了PMS
的installPackage
方法。
IPackageManager mPM
总结下PackageInstaller
安装APK,其实就是调到了PMS
的installPackage
方法进行安装。
从源码来分析:
ApplicationPackageManager
是PackageManager
的实现体,内部有成员变量IPackageManager mPM
, ApplicationPackageManager
是由ContextImpl.java
初始化的,同时初始化的还有mPM
变量
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager(); // ApplicationPackageManager中的mPM
if (pm != null) {
// ApplicationPackageManager初始化
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
--->ApplicationPackageManager构造函数如下:
ApplicationPackageManager(ContextImpl context,
IPackageManager pm) {
mContext = context;
mPM = pm;
}
---> ActivityThread.getPackageManager如下:
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
可以看出 mPM
变量就是IPackageManager.Stub
转换的代理IPackageManagerProxy
。参考 aidl自动生成类分析
public class PackageManagerService extends IPackageManager.Stub {
}
1.PackageManagerService
是 IPackageManager
在服务端的接口
2.ApplicationPackageManager
的mPM
成员或者ActivityThread.getPackageManager
,是IPackageManager
在客户端的代理接口,
PMS
的installPackage
方法继续查看源码, 内部调用了installPackageAsUser
方法
public void installPackage(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride) {
installPackageAsUser(originPath, observer, installFlags, installerPackageName,
verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
}
===>installPackageAsUser
方法,这个方法部分功能为:
INIT_COPY
消息代码如下:
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride, int userId) {
// 1.检查调用者是否有安装apk的权限
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
...
UserHandle user;
if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(userId);
}
// Only system components can circumvent runtime permissions when installing.
if ((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");
}
verificationParams.setInstallerUid(callingUid);
final File originFile = new File(originPath);
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
null, verificationParams, user, packageAbiOverride, null);
// 2.由于安装程序是一个耗时的过程,所以使用了Handler消息传递机制,发送INIT_COPY消息
mHandler.sendMessage(msg);
}
---->mHandler的定义:
final PackageHandler mHandler;
处理INIT_COPY
类型的消息,这个方法部分功能为:
connectToService
用于标识是否绑定了DefaultContainerService
,DefaultContainerService
是用于检查和复制可移动文件的服务,这是一个比较耗时的操作,因此DefaultContainerService
没有和PMS
运行在同一进程中,它运行在com.android.defcontainer
进程,通过IMediaContainerService
和PMS
进行IPC
通信MCS_BOUND
类型的消息,触发处理第一个安装请求代码如下所示:
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
// mBound用于标识是否绑定了服务,默认值为false
if (!mBound) {
//如果没有绑定服务,重新绑定,connectToService方法内部如果绑定成功会将mBound置为true
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();
//绑定服务失败则return
return;
} else {
//绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理
mPendingInstalls.add(idx, params);
}
} else {
//已经绑定服务
mPendingInstalls.add(idx, params); // 加入待安装List
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);// 发送MCS_BOUND
}
}
break;
处理MCS_BOUND
类型的消息, 如果待安装mPendingInstalls
不为空,这个方法部分功能为:
startCopy
开始复制APKmPendingInstalls.remove(0);
MCS_UNBIND
解绑服务的请求MCS_BOUND
消息继续处理剩余的安装请求代码如下所示:
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mContainerService == null) {
if (!mBound) {
...
// 绑定失败,清空安装请求队列
mPendingInstalls.clear();
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {// 待安装List不为空
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
if (params.startCopy()) { // 1.开始复制APK
// We are done... look for more work or to
// Delete pending install
//2.如果APK安装成功,删除本次安装请求
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
// 3.如果没有安装请求了,发送MCS_UNBIND解绑服务的请求
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// Unbind after a little delay, to avoid
// continual thrashing.
sendMessageDelayed(ubmsg, 10000);
}
} else {
// 4.如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
}
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
}
break;
}
由INIT_COPY
的发送消息,我们可以知道InstallParams
是HandlerParams
真正实现体,代码如下:
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
null, verificationParams, user, packageAbiOverride, null);
--->InstallParams
前面关键函数是HandlerParams
的startCopy
,也就是InstallParams
的startCopy
,调用startCopy
方法时会先自动加1,如果次数大于4次就放弃这个安装请求,代码如下:
final boolean startCopy() {
boolean res;
try {
// 1.startCopy方法尝试的次数,超过了4次,就放弃这个安装请求
if (++mRetries > MAX_RETRIES) {
...
return false;
} else {
handleStartCopy(); // 2.调用handleStartCopy
res = true;
}
} catch (RemoteException e) {
...
}
handleReturnCode();
return res;
}
===>handleStartCopy
方法在InstallParams
中实现,这个方法部分功能为:
onSd
:安装到SD卡, onInt
:内部存储即Data分区InstallParams
创建InstallArgs
对象, InstallArgs
是一个抽象类,定义了APK的安装逻辑,比如复制和重命名APK等,它有3个子类,都被定义在PMS
中,如下图所示。 private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
return new MoveInstallArgs(params);
} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
}
}
FileInstallArgs
用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(Data分区)
AsecInstallArgs
用于处理安装到ASEC中(mnt/asec)即SD卡中的APK
MoveInstallArgs
用于处理已安装APK的移动的逻辑。
对APK进行检查后就会调用InstallArgs
的copyApk
方法进行安装。
代码如下:
public void handleStartCopy() throws RemoteException {
...
// 1.确定APK的安装位置。onSd:安装到SD卡, onInt:内部存储即Data分区
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
// APK不能同时安装在SD卡和Data分区
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
// 获取APK的少量的信息
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
packageAbiOverride);
...
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// 2.判断安装的位置
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) {
...
} else {
// Override with defaults if needed.
loc = installLocationPolicy(pkgLite);
...
}
}
//3.根据InstallParams创建InstallArgs对象
final InstallArgs args = createInstallArgs(this);
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
/*
* ADB installs appear as UserHandle.USER_ALL, and can only be performed by
* UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
*/
int userIdentifier = getUser().getIdentifier();
if (userIdentifier == UserHandle.USER_ALL
&& ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
userIdentifier = UserHandle.USER_OWNER;
}
/*
* 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, userIdentifier);
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(userIdentifier, installFlags)) {
final ComponentName requiredVerifierComponent = matchComponentForVerifier(
mRequiredVerifierPackage, receivers);
if (ret == PackageManager.INSTALL_SUCCEEDED
&& mRequiredVerifierPackage != null) {
...
// 一堆检查...
}
} else {
/*
* No package verification is enabled, so immediately start
* the remote call to initiate copy using temporary file.
*/
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
===>InstallArgs
的copyApk
方法, 不同的InstallArgs
子类会有着不同的处理,这里以FileInstallArgs
为例,这个方法部分功能为:
/data/app/vmdl123456.tmp
,其中123456
是安装的sessionId
IMediaContainerService
跨进程调用DefaultContainerService
的copyPackage
方法,这个方法会在DefaultContainerService
所在的进程中将APK复制到临时存储目录,比如/data/app/vmdl 123456.tmp/base.apk
。代码如下:
int copyApk(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 {
// 1.创建临时文件存储目录
final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid);
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
...
int ret = PackageManager.INSTALL_SUCCEEDED;
// 2.通过IMediaContainerService跨进程调用DefaultContainerService的copyPackage方法
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.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);
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;
}
===>DefaultContainerService
的copyPackage
,最终调用FileInputStream
写入,代码流程如下:
public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
...
final File packageFile = new File(packagePath);
pkg = PackageParser.parsePackageLite(packageFile, 0);
return copyPackageInner(pkg, target);
...
}
---->
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
throws IOException, RemoteException {
copyFile(pkg.baseCodePath, target, "base.apk");
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
for (int i = 0; i < pkg.splitNames.length; i++) {
copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");
}
}
return PackageManager.INSTALL_SUCCEEDED;
}
---->
private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)
throws IOException, RemoteException {
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(sourcePath);
out = new ParcelFileDescriptor.AutoCloseOutputStream(
target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
Streams.copy(in, out);
} finally {
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(in);
}
}
我们回到APK的复制调用链的头部方法:HandlerParams
的startCopy
方法,在最后会调用InstallParams
的handleReturnCode
,代码如下所示:
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);
}
}
===>processPendingInstall
,这个方法部分功能为:
args.doPreInstall
安装前处理,检查APK的状态,在安装前确保安装环境的可靠,如果不可靠会清除复制的APK文件installPackageLI
安装流程args.doPostInstall
处理安装后的收尾操作,如果安装不成功,删除掉安装相关的目录与文件代码如下:
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.returnCode = currentStatus;
res.uid = -1;
res.pkg = null;
res.removedInfo = new PackageRemovedInfo();
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// 安装前处理
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
installPackageLI(args, res);// 安装
}
// 安装后收尾
args.doPostInstall(res.returnCode, res.uid);
}
....
});
}
===>installPackageLI
安装流程,这个方法部分功能为:
replace
置为true表示是替换安装/data/app/vmdl123456.tmp/base.apk
,重命名为/data/app/包名-1/base.apk
。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加,参考FileInstallArgs
的getNextCodePath
代码如下:
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
...
PackageParser pp = new PackageParser();//1
final PackageParser.Package pkg;
try {
// 1.创建PackageParser解析APK
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError("Failed parse 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) {
// 2. 检查APK的package是已存在,替换已存在的,也就是更新模式
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
String oldName = mSettings.mRenamedPackages.get(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.
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;//设置标志位表示是替换安装
}
...
}
PackageSetting ps = mSettings.mPackages.get(pkgName);
//3.查看Settings中是否存有要安装的APK的信息,如果有就获取签名信息
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
//检查签名的正确性
if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
if (!checkUpgradeKeySetLP(ps, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
return;
}
}
...
}
// Check whether the newly-scanned package wants to define an already-defined perm
// 4.遍历每个权限,对权限进行处理
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);
...
}
}
if (systemApp && onExternal) {
// 系统APP不能在SD卡上替换安装
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
return;
}
...
// 5.重命名临时文件
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
if (replace) {
//6.1 替换安装
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, volumeUuid, res);
} else {
// 6.2 安装新的APK
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res);
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
// 7.更新应用程序所属的用户
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
}
===>这里我们以新安装APK为例,会调用PMS
的installNewPackageLIF
方法,这个方法部分功能为:
PackageParser.Package
类型的newPackage
中,一个Package
的信息包含了1个base APK以及0个或者多个split APKSettings
信息,Settings
用于保存所有包的动态设置。代码如下:
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
...
try {
//1. 扫描APK
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
// 2.更新Settings信息
updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
//3.安装失败则删除APK
deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
res.removedInfo, true);
}
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
}
===>updateSettingsLI
中设置APK安装成功,代码如下:
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
UserHandle user) {
String pkgName = newPackage.packageName;
synchronized (mPackages) {
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
mSettings.writeLPr();
}
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
synchronized (mPackages) {
updatePermissionsLPw(newPackage.packageName, newPackage,
UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
? UPDATE_PERMISSIONS_ALL : 0));
// For system-bundled packages, we assume that installing an upgraded version
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (isSystemApp(newPackage)) {
// NB: implicit assumption that system package upgrades apply to all users
if (DEBUG_INSTALL) {
Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
}
if (res.origUsers != null) {
for (int userHandle : res.origUsers) {
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
userHandle, installerPackageName);
}
}
// Also convey the prior install/uninstall state
if (allUsers != null && perUserInstalled != null) {
for (int i = 0; i < allUsers.length; i++) {
if (DEBUG_INSTALL) {
Slog.d(TAG, " user " + allUsers[i]
+ " => " + perUserInstalled[i]);
}
ps.setInstalled(perUserInstalled[i], allUsers[i]);
}
// these install state changes will be persisted in the
// upcoming call to mSettings.writeLPr().
}
}
// It's implied that when a user requests installation, they want the app to be
// installed and enabled.
int userId = user.getIdentifier();
if (userId != UserHandle.USER_ALL) {
ps.setInstalled(true, userId);
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
}
}
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
// 安装完成状态
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
mSettings.writeLPr();
}
它和 AMS
的创建是类似的,启动代码位于frameworks/base/services/java/com/android/server/SystemServer.java
中,代码如下:
// zygote的main入口
public static void main(String[] args) {
new SystemServer().run();
}
===> SystemServer().run
的部分代码:
private void run() {
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.
try {
traceBeginAndSlog("StartServices");
//启动引导服务
startBootstrapServices();//3
//启动核心服务
startCoreServices();//4
//启动其他服务
startOtherServices();//5
}
}
SystemServiceManager
启动了ActivityManagerService
、PowerManagerService
、PackageManagerService
等服务。
startCoreServices
方法中则启动了DropBoxManagerService
、BatteryService
、UsageStatsService
和WebViewUpdateServic
等服务。
startOtherServices
方法中启动了CameraService
、AlarmManagerService
、VrManagerService
等服务。
这些服务的父类均为SystemService
。
可以看出,官方把系统服务分为了三种类型,分别是引导服务、核心服务和其他服务,PMS
属于引导服务
===>创建PMS
的过程位于startBootstrapServices
中,使用了PackageManagerService.main
方法,代码如下:
private void startBootstrapServices() {
...
// 创建PMS
Slog.i(TAG, "Package Manager");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
===>PackageManagerService.main
方法 ,这个方法部分功能为:
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// 1.创建PMS对象
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
// 2.将PMS注册到ServiceManager中
ServiceManager.addService("package", m);
return m;
}
==>接着看PMS
的构造过程,PMS的构造方法大概有600多行,分为5个阶段,每个阶段会打印出相应的EventLog,EventLog用于打印Android系统的事件日志。
代码如下:
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// 打印开始阶段日志
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
// 用于存储屏幕的相关信息
mMetrics = new DisplayMetrics();
// Settings用于保存所有包的动态设置
mSettings = new Settings(mPackages);
// 在Settings中添加多个默认的sharedUserId//1
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
...
mInstaller = installer;
// 创建Dex优化工具类
mPackageDexOptimizer = new PackageDexOptimizer(this);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());
getDefaultDisplayMetrics(context, mMetrics);
// 得到全局系统配置信息
SystemConfig systemConfig = SystemConfig.getInstance();
// 获取全局的groupId
mGlobalGids = systemConfig.getGlobalGids();
// 获取系统权限
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
synchronized (mInstallLock) {
// 安装APK时需要的锁,保护所有对installd的访问。
synchronized (mPackages) {//2
// 创建后台线程ServiceThread
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
// 创建PackageHandler绑定到ServiceThread的消息队列
mHandler = new PackageHandler(mHandlerThread.getLooper());//3
// 将PackageHandler添加到Watchdog的检测集中
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);//4
// 在Data分区创建一些目录
File dataDir = Environment.getDataDirectory();//5
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
// 创建多用户管理服务
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
在开始阶段中创建了很多PMS中的关键对象并赋值给PMS中的成员变量,下面简单介绍这些成员变量。
mSettings
:用于保存所有包的动态设置。注释1处将系统进程的sharedUserId
添加到Settings
中,sharedUserId
用于进程间共享数据,比如两个App的之间的数据是不共享的,如果它们有了共同的sharedUserId
,就可以运行在同一个进程中共享数据。
mInstaller
:Installer
继承自SystemService
,和PMS
、AMS
一样是系统的服务(虽然名称不像是服务),PMS
很多的操作都是由Installer
来完成的,比如APK的安装和卸载。在Installer
内部,通过IInstalld
和installd
进行Binder通信,由位于nativie层的installd来完成具体的操作。
systemConfig
:用于得到全局系统配置信息。比如系统的权限就可以通过SystemConfig
来获取。
mPackageDexOptimizer
: Dex优化的工具类。
mHandler
(PackageHandler
类型) :PackageHandler
继承自Handler
,在注释3处它绑定了后台线程ServiceThread
的消息队列。PMS
通过PackageHandler
驱动APK的复制和安装工作,参考前面的APK拷贝。
PackageHandler
处理的消息队列如果过于繁忙,有可能导致系统卡住, 因此在注释4处将它添加到Watchdog
的监测集中。
Watchdog
主要有两个用途,一个是定时检测系统关键服务(AMS
和WMS
等)是否可能发生死锁,还有一个是定时检测线程的消息队列是否长时间处于工作状态(可能阻塞等待了很长时间)。如果出现上述问题,Watchdog
会将日志保存起来,必要时还会杀掉自己所在的进程,也就是SystemServer
进程。
sUserManager
(UserManagerService
类型) :多用户管理服务。
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
// 打印扫描系统阶段日志
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
// 在/system中创建framework目录
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// Gross hack for now: we know this file doesn't contain any
// code, so don't dexopt it to avoid the resulting log spew.
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
//扫描/vendor/overlay目录下的文件
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
//扫描/system/framework 目录下的文件
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
//扫描 /system/priv-app 目录下的文件
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
//扫描/system/app 目录下的文件
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all vendor packages.
File vendorAppDir = new File("/vendor/app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
//扫描 /vendor/app 目录下的文件
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
//扫描/oem/app 目录下的文件
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
mInstaller.moveFiles();
//这个列表代表有可能有升级包的系统App
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
/*
* If this is not a system app, it can't be a
* disable system app.
*/
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
//这里的mPackages的是PMS的成员变量,代表scanDirTracedLI方法扫描上面那些目录得到的
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
//将这个系统App的PackageSetting从PMS的mPackages中移除
removePackageLI(ps, true);
//将升级包的路径添加到mExpectingBetter列表中
mExpectingBetter.put(ps.name, ps.codePath);
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
psit.remove();
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; wiping its data");
removeDataDirsLI(null, ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
//这个系统App升级包信息在mDisabledSysPackages中,但是没有发现这个升级包存在
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
}
...
/system
可以称作为System
分区,里面主要存储谷歌和其他厂商提供的Android系统相关文件和框架。Android系统架构分为应用层、应用框架层、系统运行库层(Native 层)、硬件抽象层(HAL层)和Linux内核层,除了Linux内核层在Boot分区,其他层的代码都在System
分区。下面列出 System
分区的部分子目录。
目录 | 含义 |
---|---|
system/app | 存放系统App,包括了谷歌内置的App也有厂商或者运营商提供的App |
system/framework | 存放应用框架层的jar包 |
system/priv-app | 存放特权App |
system/lib | 存放so文件 |
system/fonts | 存放系统字体文件 |
system/media | 存放系统的各种声音,比如铃声、提示音,以及系统启动播放的动画 |
系统扫描阶段的主要工作有以下3点:
// 打印扫描Data分区阶段日志
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
// 扫描/data/app目录下的文件
scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
// 扫描/data/app-private目录下的文件
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
// 扫描完Data分区后,处理possiblyDeletedUpdatedSystemApps列表
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
// 从mSettings.mDisabledSysPackages变量中移除去此应用
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
String msg;
//1:如果这个系统App的包信息不在PMS的变量mPackages中,说明是残留的App信息,后续会删除它的数据。
if (deletedPkg == null) {
msg = "Updated system package " + deletedAppName
+ " no longer exists; wiping its data";
removeDataDirsLI(null, deletedAppName);
} else {
//2:如果这个系统App在mPackages中,说明是存在于Data分区,不属于系统App,那么移除其系统权限。
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
+ deletedAppName;
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
logCriticalInfo(Log.WARN, msg);
}
//遍历mExpectingBetter列表
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
//得到系统App的升级包路径
final File scanFile = mExpectingBetter.valueAt(i);
// 3:根据系统App所在的目录设置扫描的解析参数
final int reparseFlags;
if (FileUtils.contains(privilegedAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED;
} else if (FileUtils.contains(systemAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR;
} else if (FileUtils.contains(vendorAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR;
} else if (FileUtils.contains(oemAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR;
} else {
Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
continue;
}
//将packageName对应的包设置数据(PackageSetting)添加到mSettings的mPackages中
mSettings.enableSystemPackageLPw(packageName);
try {
//扫描系统App的升级包
scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}
}
mExpectingBetter.clear();
/data
可以称为Data
分区,它用来存储所有用户的个人数据和配置文件。下面列出Data
分区部分子目录:
目录 | 含义 |
---|---|
data/app | 存储用户自己安装的App |
data/data | 存储所有已安装的App数据的目录,每个App都有自己单独的子目录 |
data/app-private | App的私有存储空间 |
data/app-lib | 存储所有App的Jni库 |
data/system | 存放系统配置文件 |
data/anr | 用于存储ANR发生时系统生成的traces.txt文件 |
// 打印扫描结束阶段日志
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
// 如果当前平台SDK版本和上次启动时的SDK版本不同,重新更新APK的授权
int updateFlags = UPDATE_PERMISSIONS_ALL;
if (ver.sdkVersion != mSdkVersion) {
Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
+ mSdkVersion + "; regranting permissions for internal storage");
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
ver.sdkVersion = mSdkVersion;
//如果是第一次启动,需要初始化所有用户定义的默认首选App
if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(this, user.id);
applyFactoryDefaultBrowserLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}
//OTA后的第一次启动,会清除代码缓存目录。
if (mIsUpgrade && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < mSettings.mPackages.size(); i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
checkDefaultBrowser();
// clear only after permissions and other defaults have been updated
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
// All the changes are done during package scanning.
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// 把Settings的内容保存到packages.xml中
mSettings.writeLPr();
扫描结束结束阶段主要做了以下几件事:
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
mRequiredVerifierPackage = getRequiredVerifierLPr();
mRequiredInstallerPackage = getRequiredInstallerLPr();
mInstallerService = new PackageInstallerService(context, this);//1
mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
mIntentFilterVerifierComponent);
} // synchronized (mPackages)
} // synchronized (mInstallLock)
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
Runtime.getRuntime().gc();
// Expose private service for system components to use.
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());//2
注释1处创建PackageInstallerService
,PackageInstallerService
是用于管理安装会话的服务,它会为每次安装过程分配一个SessionId
注释2处将PackageManagerInternalImpl
(PackageManager
的本地服务)添加到LocalServices
中,LocalServices
用于存储运行在当前的进程中的本地服务。
Android世界中有很多包,比如应用程序的APK,Android运行环境的JAR包(比如framework.jar)和组成Android系统的各种动态库so等等,由于包的种类和数量繁多,就需要进行包管理,但是包管理需要在内存中进行,而这些包都是以静态文件的形式存在的,就需要一个工具类将这些包转换为内存中的数据结构,这个工具就是包解析器PackageParser
。
再看下 前面的installPackageLI
代码:
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
...
PackageParser pp = new PackageParser();//1
final PackageParser.Package pkg;
try {
// 1.创建PackageParser解析APK
pkg = pp.parsePackage(tmpPackageFile, parseFlags);//2
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
}
可以看到安装APK时,需要先在注释1处创建PackageParser
,然后在注释2处调用PackageParser
的parsePackage
方法来解析APK。
Android5.0引入了Split APK
机制,这是为了解决65536上限以及APK安装包越来越大等问题。Split APK
机制可以将一个APK,拆分成多个独立APK。
在引入了Split APK
机制后,APK有两种分类:
Single APK
:安装文件为一个完整的APK,即base APK
。Android称其为Monolithic
。Mutiple APK
:安装文件在一个文件目录中,其内部有多个被拆分的APK,这些APK由一个 base APK
和一个或多个split APK
组成。Android称其为Cluster
。===>先看 pp.parsePackage
方法的实现,结合前面的分类,可以知道,如果要解析的packageFile
是一个目录,说明是Mutiple APK
,就需要调用parseClusterPackage
方法来解析,如果是Single APK
则调用parseMonolithicPackage
方法来解析,代码如下:
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
===>以相对复杂的parseClusterPackage
继续分析,代码如下:
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
final PackageLite lite = parseClusterPackageLite(packageDir, 0);//1
if (mOnlyCoreApps && !lite.coreApp) {//2
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + packageDir);
}
final AssetManager assets = new AssetManager();
try {
// 把base和所有split都加入assets
loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
for (String path : lite.splitCodePaths) {
loadApkIntoAssetManager(assets, path, flags);
}
}
final File baseApk = new File(lite.baseCodePath);
final Package pkg = parseBaseApk(baseApk, assets, flags);//3
if (pkg == null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse base APK: " + baseApk);
}
if (!ArrayUtils.isEmpty(lite.splitNames)) {
final int num = lite.splitNames.length;//4
pkg.splitNames = lite.splitNames;
pkg.splitCodePaths = lite.splitCodePaths;
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num];
pkg.splitPrivateFlags = new int[num];
for (int i = 0; i < num; i++) {
parseSplitApk(pkg, i, assets, flags);//5
}
}
pkg.codePath = packageDir.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
注释1处调用parseClusterPackageLite
方法用于轻量级解析目录文件,之所以要轻量级解析是因为解析APK是一个复杂耗时的操作,这里的逻辑并不需要APK所有的信息。parseClusterPackageLite
方法内部会通过parseApkLite
方法解析每个Mutiple APK
,得到每个Mutiple APK
对应的ApkLite
(轻量级APK信息),然后再将这些ApkLite
封装为一个PackageLite
(轻量级包信息)并返回。
注释2处,mOnlyCoreApps
用来指示PackageParser
是否只解析“核心”应用,“核心”应用指的是AndroidManifest
中属性coreApp
值为true
,只解析“核心”应用是为了创建一个极简的启动环境。mOnlyCoreApps
在创建PMS
时就一路传递过来,如果我们加密了设备,mOnlyCoreApps
值就为true
注释3处的parseBaseApk
方法用于解析base APK
,注释4处获取split APK
的数量,根据这个数量在注释5处遍历调用parseSplitApk
来解析每个split APK
===>先来看下parseClusterPackageLite
方法,它的调用流程如下:
private static PackageLite parseClusterPackageLite(File packageDir, int flags)
throws PackageParserException {
....
final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
for (File file : files) {
if (isApkFile(file)) {
final ApkLite lite = parseApkLite(file, flags);
...
}
--->ApkLite 的实现:
public static class ApkLite {
public final String codePath;
public final String packageName;
public final String splitName;
public final int versionCode;
public final int revisionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
public final Signature[] signatures;
public final boolean coreApp;
public final boolean multiArch;
public final boolean extractNativeLibs;
===>再来看下parseBaseApk
方法,它的调用流程如下:
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);//1
}
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
Resources res = null;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
final Package pkg = parseBaseApk(res, parser, flags, outError);//2
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
pkg.volumeUuid = volumeUuid; // 3
pkg.applicationInfo.volumeUuid = volumeUuid; // 4
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}
---->
注释1处,如果APK的路径以/mnt/expand/开头,就截取该路径获取volumeUuid
注释3处用于以后标识这个解析后的Package
注释4处的用于标识该App所在的存储卷UUID
注释2处又调用了parseBaseApk
的重载方法,可以看出当前的parseBaseApk
方法主要是为了获取和设置volumeUuid
===>继续看下parseBaseApk
重载方法,它的调用流程如下:
Package
对象pkg
AndroidManifest
中的coreApp
的值AndroidManifest
中的各个标签,比如application
、permission
、uses-sdk
、feature-group
等解析application
标签的方法为parseBaseApplication
,有近500行代码,而Application
只是AndroidManifest
众多标签的一个,这让我们更加理解了为什么此前解析APK时要使用轻量级解析了,parseBaseApk
方法主要的解析结构可以理解为以下简图。
代码如下:
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
...
// 1.创建Package对象
final Package pkg = new Package(pkgName);
boolean foundApp = false;
// 2.从资源中提取自定义属性集com.android.internal.R.styleable.AndroidManifest得到TypedArray
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
...
// 3.读取APK的AndroidManifest中的coreApp的值
pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);
//获取资源后要回收
sa.recycle();
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
}
/* Set the global "on SD card" flag */
if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
}
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
int supportsNormalScreens = 1;
int supportsLargeScreens = 1;
int supportsXLargeScreens = 1;
int resizeable = 1;
int anyDensity = 1;
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("application")) {
...
foundApp = true;
if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) { // 3
return null;
}
} else if (tagName.equals("overlay")) {
pkg.mTrustedOverlay = trustedOverlay;
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestResourceOverlay);
pkg.mOverlayTarget = sa.getString(
com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
pkg.mOverlayPriority = sa.getInt(
com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
-1);
sa.recycle();
if (pkg.mOverlayTarget == null) {
outError[0] = " does not specify a target package" ;
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
}
if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
outError[0] = " priority must be between 0 and 9999" ;
mParseError =
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
}
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("key-sets")) {
// 4.各种解析tagname....
.....
}
if (!foundApp && pkg.instrumentation.size() == 0) {
outError[0] = " does not contain an or " ;
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
}
final int NP = PackageParser.NEW_PERMISSIONS.length;
StringBuilder implicitPerms = null;
for (int ip=0; ip<NP; ip++) {
final PackageParser.NewPermissionInfo npi
= PackageParser.NEW_PERMISSIONS[ip];
if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
break;
}
if (!pkg.requestedPermissions.contains(npi.name)) {
if (implicitPerms == null) {
implicitPerms = new StringBuilder(128);
implicitPerms.append(pkg.packageName);
implicitPerms.append(": compat added ");
} else {
implicitPerms.append(' ');
}
implicitPerms.append(npi.name);
pkg.requestedPermissions.add(npi.name);
}
}
if (implicitPerms != null) {
Slog.i(TAG, implicitPerms.toString());
}
final int NS = PackageParser.SPLIT_PERMISSIONS.length;
for (int is=0; is<NS; is++) {
final PackageParser.SplitPermissionInfo spi
= PackageParser.SPLIT_PERMISSIONS[is];
if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
|| !pkg.requestedPermissions.contains(spi.rootPerm)) {
continue;
}
for (int in=0; in<spi.newPerms.length; in++) {
final String perm = spi.newPerms[in];
if (!pkg.requestedPermissions.contains(perm)) {
pkg.requestedPermissions.add(perm);
}
}
}
if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
}
if (supportsNormalScreens != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
}
if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
}
if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
}
if (resizeable < 0 || (resizeable > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
}
if (anyDensity < 0 || (anyDensity > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
}
return pkg;
}
包被解析后,最终在内存是Package
,Package
是PackageParser
的内部类,它的部分成员变量如下所示。
/**
* Representation of a full package parsed from APK files on disk. A package
* consists of a single base APK, and zero or more split APKs.
*/
public final static class Package {
public String packageName; // 包名
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames;
// TODO: work towards making these paths invariant
public String volumeUuid;
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
public String codePath;
/** Path of base APK */
public String baseCodePath;
/** Paths of any split APKs, ordered by parsed splitName */
public String[] splitCodePaths;
/** Revision code of base APK */
public int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
public int[] splitRevisionCodes;
/** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags;
/**
* Private flags of any split APKs; ordered by parsed splitName.
*
* {@hide}
*/
public int[] splitPrivateFlags;
public boolean baseHardwareAccelerated;
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
//4 大组件
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
public final ArrayList<Service> services = new ArrayList<Service>(0);
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
public ArrayList<String> protectedBroadcasts;
public ArrayList<String> libraryNames = null;
public ArrayList<String> usesLibraries = null;
public ArrayList<String> usesOptionalLibraries = null;
public String[] usesLibraryFiles = null;
public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
public ArrayList<String> mOriginalPackages = null;
public String mRealPackage = null;
public ArrayList<String> mAdoptPermissions = null;
// We store the application meta-data independently to avoid multiple unwanted references
public Bundle mAppMetaData = null;
// The version code declared for this package.
public int mVersionCode;
// The version name declared for this package.
public String mVersionName;
// The shared user id that this package wants to use.
public String mSharedUserId;
// The shared user label that this package wants to use.
public int mSharedUserLabel;
// Signatures that were read from the package.
public Signature[] mSignatures;
public Certificate[][] mCertificates;
// For use by package manager service for quick lookup of
// preferred up order.
public int mPreferredOrder = 0;
// For use by package manager to keep track of where it needs to do dexopt.
public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
// For use by package manager to keep track of when a package was last used.
public long mLastPackageUsageTimeInMills;
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
//
// // Whether the package has been stopped.
// public boolean mSetStopped = false;
// Additional data supplied by callers.
public Object mExtras;
// Applications hardware preferences
public ArrayList<ConfigurationInfo> configPreferences = null;
// Applications requested features
public ArrayList<FeatureInfo> reqFeatures = null;
// Applications requested feature groups
public ArrayList<FeatureGroupInfo> featureGroups = null;
public int installLocation;
public boolean coreApp;
/* An app that's required for all users and cannot be uninstalled for a user */
public boolean mRequiredForAllUsers;
/* The restricted account authenticator type that is used by this application */
public String mRestrictedAccountType;
/* The required account type without which this application will not function */
public String mRequiredAccountType;
/**
* Digest suitable for comparing whether this package's manifest is the
* same as another.
*/
public ManifestDigest manifestDigest;
public String mOverlayTarget;
public int mOverlayPriority;
public boolean mTrustedOverlay;
/**
* Data used to feed the KeySetManagerService
*/
public ArraySet<PublicKey> mSigningKeys;
public ArraySet<String> mUpgradeKeySets;
public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
注意4大组件那里,Activity
,Provider
, Service
都是PackageParser
的静态内部类,例如Activity
public final static class Activity extends Component<ActivityIntentInfo> {
public final ActivityInfo info;
public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
super(args, _info);
info = _info;
info.applicationInfo = args.owner.applicationInfo;
}
public void setPackageName(String packageName) {
super.setPackageName(packageName);
info.packageName = packageName;
}
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("Activity{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(' ');
appendComponentShortName(sb);
sb.append('}');
return sb.toString();
}
}
Package
简图如下:
从这个简图中可以发现Package
的数据结构是如何设计的:
Package
中存有许多组件,比如Acticity
、Provider
、Permission
等等,它们都继承基类Component
。info
数据,比如Activity
类中包含了成员变量ActivityInfo
,这个ActivityInfo
才是真正的Activity
数据。
来过滤Intent信息,因此需要IntentInfo
来保存组件的intent
信息,组件基类Component
依赖于IntentInfo
public static class Component<II extends IntentInfo> {
public final Package owner;
public final ArrayList<II> intents;
public final String className;
public Bundle metaData;
ComponentName componentName;
String componentShortName;
--->IntentInfo的代码如下:
public static class IntentInfo extends IntentFilter {
public boolean hasDefault;
public int labelRes;
public CharSequence nonLocalizedLabel;
public int icon;
public int logo;
public int banner;
public int preferred;
}
--->IntentFilter的代码如下:
public class IntentFilter implements Parcelable {
...
public static final String SCHEME_HTTPS = "https";
private int mPriority;
private final ArrayList<String> mActions;
private ArrayList<String> mCategories = null;
private ArrayList<String> mDataSchemes = null;
private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
private ArrayList<AuthorityEntry> mDataAuthorities = null;
private ArrayList<PatternMatcher> mDataPaths = null;
private ArrayList<String> mDataTypes = null;
private boolean mHasPartialTypes = false;
}
IntentInfo
有三个子类ActivityIntentInfo
、ServiceIntentInfo
和ProviderIntentInfo
,不同组件依赖的IntentInfo
会有所不同,如下:
public final class Activity extends Component<ActivityIntentInfo>
public final static class Service extends Component<ServiceIntentInfo>
public final static class Provider extends Component<ProviderIntentInfo>
VirtualApp中解析后的数据都保存在PackageParser
类中,由PackageParserEx
(PackageParserEx
扩展了PackageParser
)解析,对外的数据是VPackage
类
VA自建的android.content.pm.PackageParse
,它其实更多的意义是占位类,让反射方式更优雅,它和系统的android.content.pm.PackageParse
保持一致,但实际上,系统解析得到的android.content.pm.PackageParse
,还是系统那一份。
PackageParser
类最底层数据仍是IntentInfo
,如下:
public static class IntentInfo extends IntentFilter {
public boolean hasDefault;
public int labelRes;
public CharSequence nonLocalizedLabel;
public int icon;
public int logo;
public int banner;
}
同样有一个Component
基类,如下:
public static class Component<II extends IntentInfo> {
public Package owner;
public ArrayList<II> intents;
public String className;
public Bundle metaData;
public ComponentName getComponentName() {
return null;
}
}
用getComponentName
代替了 ComponentName componentName;
前面提到Package
中存有许多组件,比如Acticity
、Provider
、Permission
等等,它们都继承基类Component
,另外前面提到Package
中每个组件都包含一个info
数据,info
数据才是真正的数据,VA采用了同样的构造方式,如下:
public final static class Activity extends Component<ActivityIntentInfo> {
public ActivityInfo info;
}
public class ActivityIntentInfo extends IntentInfo {
public Activity activity;
}
对比系统的,完全一致:
public final static class Activity extends Component<ActivityIntentInfo> {
public final ActivityInfo info;
...
}
public final static class ActivityIntentInfo extends IntentInfo {
public final Activity activity;
...
对应Package
类也 相对砍掉了不少变量,其中SigningDetails
是API28
才增加的新变量
public class Package {
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
public final ArrayList<Service> services = new ArrayList<Service>(0);
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
public Signature[] mSignatures;
public SigningDetails mSigningDetails; // API 28
public Bundle mAppMetaData;
public Object mExtras;
public String packageName;
public int mPreferredOrder;
public String mSharedUserId;
public ArrayList<String> usesLibraries;
public int mVersionCode;
public ApplicationInfo applicationInfo;
public String mVersionName;
// Applications hardware preferences
public ArrayList<ConfigurationInfo> configPreferences = null;
// Applications requested features
public ArrayList<FeatureInfo> reqFeatures = null;
public int mSharedUserLabel;
}
PackageParse
类没有解析函数,保存一些仿系统的数据类的简化版,对应的Parcelable
实现为VPackage
解析代码位于PackageParserEx
中
PackageParse
类位于android.content.pm
,这和系统保持一致
PackageParse
类对应的Parcelable
实现为VPackage
类,
比如PackageParse.IntentInfo
对应VPackage.IntentInfo
,VPackage.IntentInfo
提供了相应的构造函数进行转换
public static class IntentInfo implements Parcelable {
...
public IntentInfo(PackageParser.IntentInfo info) {
this.filter = info;
this.hasDefault = info.hasDefault;
this.labelRes = info.labelRes;
if (info.nonLocalizedLabel != null) {
this.nonLocalizedLabel = info.nonLocalizedLabel.toString();
}
this.icon = info.icon;
this.logo = info.logo;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
this.banner = info.banner;
}
}
}
同样的,PackageParse.Component
对应VPackage.Component
,VPackage.Component
提供了相应的构造函数进行转换
public Component(PackageParser.Component component) {
this.className = component.className;
this.metaData = component.metaData;
}
同理,一一对应,VPackage
均提供了相应的构造函数进行转换
PackageParse.ActivityIntentInfo
对应VPackage.ActivityIntentInfo
PackageParse.ServiceIntentInfo
对应VPackage.ServiceIntentInfo
PackageParse.ProviderIntentInfo
对应VPackage.ProviderIntentInfo
PackageParse.Activity
对应VPackage.ActivityComponent
PackageParse.Service
对应VPackage.ServiceComponent
PackageParse.Provider
对应VPackage.ProviderComponent
PackageParse.Instrumentation
对应VPackage.InstrumentationComponent
PackageParse.Permission
对应VPackage.PermissionComponent
PackageParse.PermissionGroup
对应VPackage.PermissionGroupComponent
PackageParserEx
继承于PackageParse
类,类似于系统的PackageParse
类,它提供了parsePackage
接口,这个函数第一行是:
PackageParser parser = PackageParserCompat.createParser(packageFile);
VA自建的android.content.pm.PackageParse
,它其实更多的意义是占位符,让反射方式更优雅,它和系统的android.content.pm.PackageParse
保持一致,但实际上,系统解析得到的android.content.pm.PackageParse
,所以这里返回的还是系统的那一份PackageParser
,不要理解为VA的那一份
PackageParserCompat
是一个包装类,内部通过区分APK版本号来反射系统的android.content.pm.PackageParse
parsePackage
代码如下:
public static VPackage parsePackage(File packageFile) throws Throwable { // 59
PackageParser parser = PackageParserCompat.createParser(packageFile);
PackageParser.Package p = PackageParserCompat.parsePackage(parser, packageFile, 0);
...
return buildPackageCache(p);
}
-->PackageParserCompat.createParser代码如下:
public static PackageParser createParser(File packageFile) {
if (API_LEVEL >= M) {
return PackageParserMarshmallow.ctor.newInstance();
...
占位类的好处是可以直接调用系统隐藏类的变量,不能再通过反射方式去获取了, 如下图:
buildPackageCache
方法用于把将系统的Package.Package
转换成可以序列化的 VPackage
类型
VAMS
中安装包的函数是installPackageImpl
,以下是全流程跟进:
假定我们的安装包路径是:/data/app/com.hgy413.refclass-xxx==/base.apk
===> 1.利用PackageParserEx.parsePackage(packageFile);
把base.apk
解析成 VPackage pkg
。
内部仍是利用系统的android.content.pm.PackageParser
解包成PackageParser.Package
。
虽然我们定义了一个PackageParser
,但它的作用就是简单的避免反射调用系统的android.content.pm.PackageParser
。
PackageParser.Package p = PackageParserCompat.parsePackage(parser, packageFile, 0);
然后通过buildPackageCache
把PackageParser.Package
转成 VPackage pkg
。
最后通过addOwner
把VPackage.ActivityComponent
, VPackage.ServiceComponent
等的owner
设置为 VPackage pkg
自身。
如果是google service
,还需要加上 flags |= ApplicationInfo.FLAG_PERSISTENT;
。
===> 2.判断是否需要升级
PackageCacheManager
类:
它的成员 ArrayMap
记录了所有的 VPackage
, key
为包名。
而VPackage
的mExtras
成员变量中又记录了PackageSetting
对象,所以PackageSetting
对象和 VPackage
就关联起来了。
升级逻辑如下:
首先去PackageCacheManager
类中查找是否已存在相同包名的 VPackage
,不存在就继续 。
如果存在,检查传入的InstallOptions.updateStrategy
值,默认是COMPARE_VERSION
,也就是比较新旧安装包的versioncode
,仅当新的>旧的才覆盖安装。
如果需要升级,就要调用VActivityManagerService.get().killAppByPkg
把原来的进程kill掉,并从PACKAGE_CACHE
中移除原来的VPackage
。如果不需要升级,就直接返回升级失败。
===> 3.初始化PackageSetting ps
对象
如果PACKAGE_CACHE
中已存在VPackage
,就取VPackage
的mExtras
成员变量,否则创建一个新的PackageSetting ps
对象。
===> 4.复制abi下的so文件到virtual目录
NativeLibraryHelperCompat.getSupportAbiList
通过zip解压遍历base.apk
得到它内部有哪些abi
,也就是base.apk
的lib
目录下有哪些abi
,如armeabi-v7a
,x86
等。
如果abi
有arm64-v8a
,x86_64
,mips64
中一个目录,就认为这个apk支持x64, 这种属性通过PackageSetting ps.flag
来记录
if (support32bit) {
if (support64bit) {
ps.flag = PackageSetting.FLAG_RUN_BOTH_32BIT_64BIT;
} else {
ps.flag = PackageSetting.FLAG_RUN_32BIT;
}
} else {
ps.flag = PackageSetting.FLAG_RUN_64BIT;
}
NativeLibraryHelperCompat.copyNativeBinaries
执行复制abi
操作,例如把/data/app/com.hgy413.refclass-xxx==/base.apk
中的lib/x86/libv++.so
拷贝到/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/libv++.so
,系统安装apk时,系统会把abi
解压到data/app/com.hgy.ndk/lib
, VA以类似的方式保存在它的virtual
目录中, 差别是它把x86
这个abi
目录去掉了。
默认如果是系统安装过的apk,则useSourceLocationApk=true
, 这时使用外部的apk。
但如果是未被安装的apk安装包,则useSourceLocationApk=false
, 这时需要做apk拷贝。
例如:把/data/app/com.hgy413.refclass-xxx==/base.apk
拷贝到/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/base.apk
,并把packageFile
指向拷贝后的目录。
===> 5.设置PackageSetting ps
对象
设置以下信息到ps
中,在前面还设置了ps.flag
ps.appMode = useSourceLocationApk ? MODE_APP_USE_OUTSIDE_APK : MODE_APP_COPY_APK;
ps.packageName = pkg.packageName;
ps.appId = VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg));
if (res.isUpdate) {
ps.lastUpdateTime = installTime;
} else {
ps.firstInstallTime = installTime;
ps.lastUpdateTime = installTime;
for (int userId : VUserManagerService.get().getUserIds()) {
boolean installed = userId == 0;// 默认用户 userId = 0时,installed为true
ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed);
}
}
---> ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed);
public class PackageUserState implements Parcelable {
public boolean launched;
public boolean hidden;
public boolean installed;
}
VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg));
仿系统的UMS
机制,默认appid
从10001
开始,依次递增。
ps.setUserState
内部会针对每个用户环璋生成一个PackageUserState
,并记录这个ps
在每个用户环境的安装状态。
默认用户环境(userid=0
)是launched = false, hidden = false, installed = true;
, 其余用户环境是launched = false, hidden = false, installed = false;
。
简单的说,PackageSetting
记录了安装时间,更新时间,每个用户环境的安装状态,包名,appid
, 是否拷贝了apk, 是否支持x64,等信息。
===> 6.把VPackage pkg
写入package.ini
及signature.ini
文件
PackageParserEx.savePackageCache(pkg);
所做的操作:
virtual/data/app/packageName/package.ini
,以及virtual/data/app/packageName/signature.ini
Parcel
方式把pkg
写入到package.ini
中:(在loadPackageInnerLocked
中会跨进程从package.ini
读取pkg
) pkg.writeToParcel(p, 0);
FileOutputStream fos = new FileOutputStream(cacheFile);
fos.write(p.marshall());
fos.close();
Parcel
方式把pkg.mSignatures
写入到signature.ini
中===> 7.把VPackage pkg
和PackageSetting ps
都存在PackageCacheManager
中
PackageParserEx.initApplicationInfoBase(ps, pkg);
PACKAGE_CACHE.put(pkg.packageName, pkg); // 存入`VPackage pkg`
pkg.mExtras = ps; // 存入`PackageSetting ps`
VPackageManagerService.get().analyzePackageLocked(pkg);
PackageParserEx.initApplicationInfoBase(ps, pkg);
就是把pkg.ApplicationInfo
根据ps
做一些初始化,如uid
,sharedLibraryFiles
===> 8. 接第7点的VPackageManagerService.get().analyzePackageLocked(pkg)
继续分析:
主要是VPMS
保存VPackage pkg
的一些信息
activities
到mActivities
。mActivities
的类型是ActivityIntentResolver
,它内部的addActivity
函数如下: public final void addActivity(VPackage.ActivityComponent a, String type) {
mActivities.put(a.getComponentName(), a);
final int NI = a.intents.size();
for (int j = 0; j < NI; j++) {
VPackage.ActivityIntentInfo intent = a.intents.get(j);
if (intent.filter.getPriority() > 0 && "activity".equals(type)) {
intent.filter.setPriority(0);
Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity " + a.className
+ " with priority > 0, forcing to 0");
}
addFilter(intent);
}
}
ComponentName
类由packageName
和className
组成,例如:mClass = com.hgy.ndk.MainActivity
, mPackage = com.hgy.ndk
。
所有的activity
都被ActivityIntentResolver
记录到它的mActivities
中,key
是ComponentName
:
HashMap
所有的intent
都被ActivityIntentResolver
记录到它的mFilters
中:
private HashSet
同时intent
也会被解析出action
之类的字符串加入到内部mActionToFilter
, schemes
字符串加入到内部mSchemeToFilter
以获取action
字符串为例:
VPackage.ActivityComponent a
--->取第1个测试下:
VPackage.ActivityIntentInfo intent = a.intents.get(0);
--->
Iterator<String> i = f.filter.actionsIterator()
--->遍历Iterator<String> i,就可以得到android.intent.action.MAIN这种字符串了,加入mActionToFilter:
register_intent_filter(f, f.filter.actionsIterator(), mActionToFilter, " Action: ");
这部分代码具体参考了系统的PackageManagerService.ActivityIntentResolver
。
services
到mServices
。mServices
的类型是ServiceIntentResolver
,它内部的addService
函数如下: public final void addService(VPackage.ServiceComponent s) {
mServices.put(s.getComponentName(), s);
final int NI = s.intents.size();
int j;
for (j = 0; j < NI; j++) {
VPackage.ServiceIntentInfo intent = s.intents.get(j);
addFilter(intent);
}
}
receivers
到mReceivers
。mReceivers
的类型同样是ActivityIntentResolver
,所以它和1唯一的区别是传入的type是"receiver"
。 mReceivers.addActivity(a, "receiver");
providers
到mProviders
。 N = pkg.providers.size();
for (int i = 0; i < N; i++) {
VPackage.ProviderComponent p = pkg.providers.get(i);
if (p.info.processName == null) {
p.info.processName = p.info.packageName;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mProviders.addProvider(p);
}
String names[] = p.info.authority.split(";");
synchronized (mProvidersByAuthority) {
for (String name : names) {
if (!mProvidersByAuthority.containsKey(name)) {
mProvidersByAuthority.put(name, p);
}
}
}
mProvidersByComponent.put(p.getComponentName(), p);
}
mProviders
的类型是ProviderIntentResolver
, mProviders.addProvider(p);
这部分和1非常类似。
另外它要取得authority
保存到mProvidersByAuthority
中,它也会保存到mProvidersByComponent
中,这是为了方便通过authority
或ComponentName
快速查询到 VPackage.ProviderComponent
。
permissions
到mPermissions
,permissionGroups
到mPermissionGroups
,例如:
下面的permission.info.name
对应就是android.permission.SAFE_ACCESS
,代码如下:
N = pkg.permissions.size();
for (int i = 0; i < N; i++) {
VPackage.PermissionComponent permission = pkg.permissions.get(i);
mPermissions.put(permission.info.name, permission);
}
N = pkg.permissionGroups.size();
for (int i = 0; i < N; i++) {
VPackage.PermissionGroupComponent group = pkg.permissionGroups.get(i);
mPermissionGroups.put(group.className, group);
}
requestedPermissions
中的危险权限到mDangerousPermissions
,例如:<uses-permission android:name="android.permission.WRITE_SOCIAL_STREAM" />
<uses-permission android:name="android.permission.READ_SOCIAL_STREAM" />
这里会通过PermissionCompat.findDangerousPermissions
来确认请求的是否为危险权限,如果是,则加入mDangerousPermissions
中,危险权限包含了这些:
public static Set<String> DANGEROUS_PERMISSION = new HashSet<String>() {{
// CALENDAR group
add(Manifest.permission.READ_CALENDAR);
add(Manifest.permission.WRITE_CALENDAR);
// CAMERA
add(Manifest.permission.CAMERA);
// CONTACTS
add(Manifest.permission.READ_CONTACTS);
add(Manifest.permission.WRITE_CONTACTS);
add(Manifest.permission.GET_ACCOUNTS);
// LOCATION
add(Manifest.permission.ACCESS_FINE_LOCATION);
add(Manifest.permission.ACCESS_COARSE_LOCATION);
// PHONE
add(Manifest.permission.READ_PHONE_STATE);
add(Manifest.permission.CALL_PHONE);
if (Build.VERSION.SDK_INT >= 16) {
add(Manifest.permission.READ_CALL_LOG);
add(Manifest.permission.WRITE_CALL_LOG);
}
add(Manifest.permission.ADD_VOICEMAIL);
add(Manifest.permission.USE_SIP);
add(Manifest.permission.PROCESS_OUTGOING_CALLS);
// SMS
add(Manifest.permission.SEND_SMS);
add(Manifest.permission.RECEIVE_SMS);
add(Manifest.permission.READ_SMS);
add(Manifest.permission.RECEIVE_WAP_PUSH);
add(Manifest.permission.RECEIVE_MMS);
add(Manifest.permission.RECORD_AUDIO);
// STORAGE
add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (Build.VERSION.SDK_INT >= 16) {
add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (Build.VERSION.SDK_INT >= 20) {
// SENSORS
add(Manifest.permission.BODY_SENSORS);
}
}};
是官方定义的权限,是调用别人的东西的时候自己需要声明的权限,
是自己定义的权限,就是别人调用这个程序时需要用
来声明。
===> 9. 把PackageCacheManager
的内容写入到文件packages.ini
前面提到了PackageCacheManager
类包含了所有的VPackage
及PackageSetting
数据,所以这里以Parcel写文件的方式把PackageCacheManager
类保存到virtual/data/app/system/packages.ini
中。
后续会在VDeviceManagerService
中读取它们。
===> 10. 如果是支持32位又未被系统安装的apk(即sd卡下的apk安装包),尝试把apk解析成dex,并动态加载dex。
if (support32bit && !useSourceLocationApk) {
DexOptimizer.optimizeDex(packageFile.getPath(), VEnvironment.getOdexFile(ps.packageName).getPath());
}
以/data/app/com.hgy413.refclass-xxx==/base.apk
为例,主体逻辑如下:
DexOptimizer.optimizeDex
传入参数分别为/data/app/com.hgy413.refclass-xxx==/base.apk
及/data/data/io.busniess.va/virtual/opt/data@[email protected]@[email protected]
。
判断是否为art
,并且在android5.0-androi7.1之间,如果是,则调用 DexOptimizer.interpretDex2Oat
, interpretDex2Oat
这个函数内部是调用了系统的dex2oat
cmd命令来生成oat
的,它被广泛使用,如微信的tinker。
调用DexFile.loadDex(dexFilePath, optFilePath, 0)
===> 11. 是否通知安装完成。
默认在AppRepository.addVirtualApp
中初始化InstallOptions
的notify=false
。
public InstallResult addVirtualApp(AppInfoLite info) { // 174
InstallOptions options = InstallOptions.makeOptions(info.notCopyApk, false, InstallOptions.UpdateStrategy.COMPARE_VERSION);
在notify=true
时,触发通知逻辑,允许外部获得安装回调,代码如下:
private void notifyAppInstalled(PackageSetting setting, int userId) {
final String pkg = setting.packageName;
int N = mRemoteCallbackList.beginBroadcast();
while (N-- > 0) {
try {
if (userId == -1) {
mRemoteCallbackList.getBroadcastItem(N).onPackageInstalled(pkg);
mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(0, pkg);
} else {
mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(userId, pkg);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
sendInstalledBroadcast(pkg, new VUserHandle(userId));
mRemoteCallbackList.finishBroadcast();
VAccountManagerService.get().refreshAuthenticatorCache(null);
}
--->
RemoteCallbackList<IPackageObserver> mRemoteCallbackList = new RemoteCallbackList<>()
--->客户端注册:
public void registerObserver(IPackageObserver observer) {
try {
getService().registerObserver(observer);
} catch (RemoteException e) {
VirtualRuntime.crash(e);
}
}
mRemoteCallbackList
由VirtualCore.registerObserver
注册。
sendInstalledBroadcast
会广播ACTION_PACKAGE_ADDED
消息,String ACTION_PACKAGE_ADDED = "virtual." + Intent.ACTION_PACKAGE_ADDED;
,代码如下:
public void sendBroadcastAsUser(Intent intent, VUserHandle user) { // 1150
// intent包装一次设置成va自定义的action
// eg: intent.setAction("virtual.android.intent.action.PACKAGE_ADDED")
SpecialComponentList.protectIntent(intent);
Context context = VirtualCore.get().getContext();
if (user != null) {
intent.putExtra("_VA_|_user_id_", user.getIdentifier());
}
context.sendBroadcast(intent);
}
===> 12.客户端发起安装,接收安装结果:
客户端点击安装的代码流程如下:
添加App按钮点击事件为HomeActivity.onAddAppButtonClick
—>
ListAppActivity.gotoListApp(this);
请求的requestCode
为VCommends.REQUEST_SELECT_APP
—>
ListAppActivity
为显示系统已安装Apk界面,它由mViewPager
构成:
mViewPager.setAdapter(new AppPagerAdapter(getSupportFragmentManager()));
—>
AppPagerAdapter
一般是两个ListAppFragment
组成, 第一页是设备上已安装的apk,和存储中下载好的可安装的apk包。
第一页dirs.add(null)
; 所以可以根据是否为null,来确认是否取得已安装apk还是下载的apk包。
new ListAppPresenterImpl(getActivity(), this, getSelectFrom()).start();
// 获得App列表(系统已安装的或系统内部存储已安装)。
内部通过Context.getPackageManager().getInstalledPackages(PackageManager.GET_PERMISSIONS)
取得系统已安装的Apk列表
或通过findAndParseAPKs
来遍历SCAN_PATH_LIST
文件夹列表取得可安装的apk包。
—>
选中后的item操作位于ListAppFragment.onViewCreated
中,
mInstallButton.setOnClickListener( v -> { // 点击安装软件
Integer[] selectedIndices = mAdapter.getSelectedIndices();
ArrayList<AppInfoLite> dataList = new ArrayList<AppInfoLite>(selectedIndices.length);
for (int index : selectedIndices) {
AppInfo info = mAdapter.getItem(index);
dataList.add(new AppInfoLite(info));
}
Intent data = new Intent();
data.putParcelableArrayListExtra(VCommends.EXTRA_APP_INFO_LIST, dataList);
getActivity().setResult(Activity.RESULT_OK, data);
getActivity().finish();
});
—>
getActivity().finish()
后响应起始请求的requestCode
(VCommends.REQUEST_SELECT_APP
)
protected void onActivityResult(int requestCode, int resultCode, Intent data) { // 390
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == VCommends.REQUEST_SELECT_APP) {
if (resultCode == RESULT_OK && data != null) {
List<AppInfoLite> appList = data.getParcelableArrayListExtra(VCommends.EXTRA_APP_INFO_LIST);
if (appList != null) {
for (AppInfoLite info : appList) {
mPresenter.addApp(info);
}
}
}
}
—>
mPresenter.addApp(info);
,其中mPresenter = new HomePresenterImpl(this);
–>
HomePresenterImpl.addApp
内部使用了 jdeferred库异步安装,异步处理返回结果
public void addApp(AppInfoLite info) {
class AddResult {
private PackageAppData appData;
private int userId;
}
AddResult addResult = new AddResult();
ProgressDialog dialog = ProgressDialog.show(mActivity, null, mActivity.getString(R.string.tip_add_apps));
VUiKit.defer().when(() -> {
...
InstallResult res = mRepo.addVirtualApp(info);
...
}
}).then((res) -> {
addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);
}).fail((e) -> {
dialog.dismiss();
}).done(res -> {
if (addResult.userId == 0) {
PackageAppData data = addResult.appData;
data.isLoading = true;
mView.addAppToLauncher(data);
handleLoadingApp(data);
} else {
// 多用户处理
...
}
dialog.dismiss();
});
}
–>
InstallResult res = mRepo.addVirtualApp(info);
安装,mRepo = new AppRepository(mActivity);
–>
进入AppRepository
类中:
public InstallResult addVirtualApp(AppInfoLite info) {
InstallOptions options = InstallOptions.makeOptions(info.notCopyApk, false, InstallOptions.UpdateStrategy.COMPARE_VERSION);
return VirtualCore.get().installPackageSync(info.path, options);
}
--->VirtualCore.get().installPackageSync的代码实现:
public InstallResult installPackageSync(String apkPath, InstallOptions options) {
final ConditionVariable lock = new ConditionVariable();
final InstallResult[] out = new InstallResult[1];
installPackage(apkPath, options, new InstallCallback() {
@Override
public void onFinish(InstallResult result) {
out[0] = result;
lock.open();
}
});
lock.block();
return out[0];
}
--->installPackage的代码实现:
public void installPackage(String apkPath, InstallOptions options, final InstallCallback callback) {
ResultReceiver receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
resultData.setClassLoader(InstallResult.class.getClassLoader());
if (callback != null) {
InstallResult res = resultData.getParcelable("result");
callback.onFinish(res);
}
}
};
try {
getService().installPackage(apkPath, options, receiver);
} catch (RemoteException e) {
VirtualRuntime.crash(e);
}
}
getService().installPackage(apkPath, options, receiver);
会调到VAMS
中安装包的函数是installPackageImpl
,也就是起始分析的地方。
onReceiveResult
中接收安装结果。
回到 HomePresenterImpl.addApp
函数, 再看一次:
public void addApp(AppInfoLite info) {
class AddResult {
private PackageAppData appData;
private int userId;
}
AddResult addResult = new AddResult();
ProgressDialog dialog = ProgressDialog.show(mActivity, null, mActivity.getString(R.string.tip_add_apps));
VUiKit.defer().when(() -> {
...
InstallResult res = mRepo.addVirtualApp(info);
...
}
}).then((res) -> {
addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);
}).fail((e) -> {
dialog.dismiss();
}).done(res -> {
if (addResult.userId == 0) {// 默认用户
PackageAppData data = addResult.appData;
data.isLoading = true;
mView.addAppToLauncher(data);
handleLoadingApp(data);
} else {
// 多用户处理
...
}
dialog.dismiss();
});
}
在安装完成后,会返回InstallResult res
, res.isSuccess=ture
表示成功,之后执行:
addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);
PackageAppData
类描述了它在VA中显示的名字和图标,如下定义:
public class PackageAppData extends AppData {
public String packageName;
public String name;
public Drawable icon;
而PackageAppDataStorage
类用于缓存所有的PackageAppData
,它的acquire函数定义如下:
public PackageAppData acquire(String packageName) {
PackageAppData data;
synchronized (packageDataMap) {
data = packageDataMap.get(packageName);// 先从本地缓存取
if (data == null) {
data = loadAppData(packageName);// 如果缓存没有,就从远程VAMS去取
}
}
return data;
}
—>loadAppData
尝试从VPMS
去取,如果成功,就加入本地缓存, 代码如下:
private PackageAppData loadAppData(String packageName) { // 45
InstalledAppInfo setting = VirtualCore.get().getInstalledAppInfo(packageName, 0);
....
PackageAppData data = new PackageAppData(App.getApp(), setting);
packageDataMap.put(packageName, data);// 如果成功,就加入本地缓存
...
}
—>InstalledAppInfo setting
由VAMS
交互取得,流程如下:
--->VirtualCore类中的getInstalledAppInfo:
public InstalledAppInfo getInstalledAppInfo(String pkg, int flags) {
return getService().getInstalledAppInfo(pkg, flags);
}
--->调用到VAMS中:
public InstalledAppInfo getInstalledAppInfo(String packageName, int flags) {
synchronized (PackageCacheManager.class) {
if (packageName != null) {
PackageSetting setting = PackageCacheManager.getSetting(packageName);
if (setting != null) {
return setting.getAppInfo();
}
}
return null;
}
}
可以看到就是从前面提到的PackageCacheManager
类中取。
—>将InstalledAppInfo setting
转换成 PackageAppData data
,PackageAppData
的构造函数如下:
public PackageAppData(Context context, InstalledAppInfo installedAppInfo) {
this.packageName = installedAppInfo.packageName;
this.isFirstOpen = !installedAppInfo.isLaunched(0);
loadData(context, installedAppInfo.getApplicationInfo(installedAppInfo.getInstalledUsers()[0]));
}
--->loadData实现如下:
private void loadData(Context context, ApplicationInfo appInfo) { // 28
PackageManager pm = context.getPackageManager();
name = appInfo.loadLabel(pm).toString();
icon = appInfo.loadIcon(pm);
}
—>loadData中第二个参数ApplicationInfo appInfo
由VPMS
交互取得,流程如下:
public ApplicationInfo getApplicationInfo(int userId) {
return VPackageManager.get().getApplicationInfo(packageName, 0, userId);
}
--->VPackageManager类中的getApplicationInfo:
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
return getService().getApplicationInfo(packageName, flags, userId);
}
--->远程VPMS中的getApplicationInfo:
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
...
VPackage p = mPackages.get(packageName);
if (p != null) {
PackageSetting ps = (PackageSetting) p.mExtras;
return PackageParserEx.generateApplicationInfo(p, flags, ps.readUserState(userId),
userId);
}
}
return null;
}
--->PackageParserEx.generateApplicationInfo:
public static ApplicationInfo generateApplicationInfo(VPackage p, int flags,
PackageUserState state, int userId) {
...
ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
if ((flags & PackageManager.GET_META_DATA) != 0) {
ai.metaData = p.mAppMetaData;
}
initApplicationAsUser(ai, userId);
return ai;
}
可以看出VPMS
返回的是VPackage.applicationInfo
。
—>最后显示图标出来:
}).done(res -> {
if (addResult.userId == 0) {// 默认用户
PackageAppData data = addResult.appData;
data.isLoading = true;
mView.addAppToLauncher(data); // HomeActivity
handleLoadingApp(data);
--->handleLoadingApp:
private void handleLoadingApp(AppData data) {
VUiKit.defer().when(() -> {
....
}).done((res) -> {
if (data instanceof PackageAppData) {
((PackageAppData) data).isLoading = false;
((PackageAppData) data).isFirstOpen = true;
} else if (data instanceof MultiplePackageAppData) {
((MultiplePackageAppData) data).isLoading = false;
((MultiplePackageAppData) data).isFirstOpen = true;
}
mView.refreshLauncherItem(data);
});
}
也就是通过HomeActivity
的addAppToLauncher
及refreshLauncherItem
加载和显示安装APK的图标。
参考:
Android包管理机制