PackageManagerService启动流程和APK安装流程(Android 10)
PackageManagerService简称PKMS,Android系统的核心服务之一,是在SystemServer的run方法中的startBootstrapServices启动的,管理者着所有跟Package相关的工作,常见的比如安装,卸载,信息查询等,主要完成以下核心功能:
- 解析AndroidNanifest.xml清单文件,解析清单文件中的所有节点信息。
- 扫描.apk文件,安装系统应用,安装本地应用等。
- 管理本地应用,主要有, 安装,卸载,应用信息查询等。
PKMS调用方式
客户端可通过Context.getPackageManager()获得ApplicationPackageManager对象, 而mPM指向的是Proxy代理,当调用到mPM.方法后,将会调用到IPackageManager的Proxy代理方法,然后通过Binder机制中的mRemote与服务端PackageManagerService通信,并调用到PackageManagerService的方法。
image.pngBinder服务端:PackageManagerService继承于IPackageManager.Stub;
Binder客户端:ApplicationPackageManager(简称APM)的成员变量mPM
继承于IPackageManager.Stub.Proxy; 本身APM是继承于PackageManager对象。
简单的调用如下:
/**
* 得到应用层序的版本名称
*
* @return
*/
private String getVersionName() {
PackageManager packageManager = getPackageManager();
try {
// 得到apk的功能清单文件:为了防止出错直接使用getPackageName()方法获得包名
// packageManager.getPackageInfo("com.xxx.xxx", 0);
PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
//返回版本名称
return packageInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
return "";
}
}
复制代码
PKMS启动过程分析
首先描述一下大致的启动流程:SystemServer.startBootstrapServices()函数中启动PKMS服务,再调用startOtherServices()函数中对dex优化,磁盘管理功能,让PKMS进入systemReady状态。
再来看一下PKMS的启动时序图和流程图,有助于我们了解大概的类调用和启动流程,下面在进行详细分析
PKMS启动时序图
image.pngPKMS启动流程图
image.png具体步骤分析
第一步到第四步,都在startBootstrapServices()中,首先启动Intaller服务,也就是安装器,随后判断当前设备是否处于加密状态,如果只是解析核心应用,接着调用PKMS的静态方法main来创建pms对象。
- 第一步:启动Installer服务(阻塞等待),以便有机会创建具有适当权限的关键目录,如/data/user,我们需要在初始化其他服务之前完成此任务
Installer installer = mSystemServiceManager.startService(Installer.class);
mActivityManagerService.setInstaller(installer);
复制代码
- 第二步:获取设备是否加密(手机设置密码),如果设备加密了,则只解析"core"应用
// Only run "core" apps if we're encrypting the device.
String cryptState = VoldProperties.decrypt().orElse("");
复制代码
- 第三步: 调用PKMS的main方法初始化PackageManagerService,其中调用PackageManagerService()构造函数创建了PKMS对象
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
//main方法
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
// 检查Package编译相关系统属性
PackageManagerServiceCompilerMapping.checkProperties();
//执行pkms构造方法
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
//启动部分应用服务于多用户场景
m.enableSystemUserPackages();
//往ServiceManager中注册"package"和"package_native"
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
复制代码
- 第四步:如果设备没有加密,操作它。管理 A/B OTA dexopting.
// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
// Note: this isn't needed during decryption (we don't have /data anyways).
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
traceBeginAndSlog("StartOtaDexOptService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("moveab");
OtaDexoptService.main(mSystemContext, mPackageManagerService);
} catch (Throwable e) {
reportWtf("starting OtaDexOptService", e);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
traceEnd();
}
}
}
复制代码
第五,六,七步都在startOtherServices()方法中。
- 第五步:如果设备没有加密,执行updatePackagesIfNeeded,完成Dex优化等
mPackageManagerService.updatePackagesIfNeeded();
//updatePackagesIfNeeded
@Override
public void updatePackagesIfNeeded() {
enforceSystemOrRoot("Only the system can request package update");
// We need to re-extract after an OTA.
boolean causeUpgrade = isDeviceUpgrading();
// First boot or factory reset.
// Note: we also handle devices that are upgrading to N right now as if it is their
// first boot, as they do not have profile data.
boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;
// We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
return;
}
List<PackageParser.Package> pkgs;
synchronized (mPackages) {
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
final long startTime = System.nanoTime();
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* bootComplete */);
final int elapsedTimeSeconds =
(int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
MetricsLogger.histogram(mContext, "opt_dialog_num_dexopted", stats[0]);
MetricsLogger.histogram(mContext, "opt_dialog_num_skipped", stats[1]);
MetricsLogger.histogram(mContext, "opt_dialog_num_failed", stats[2]);
MetricsLogger.histogram(mContext, "opt_dialog_num_total", getOptimizablePackages().size());
MetricsLogger.histogram(mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}
复制代码
- 第六步:执行performFstrimIfNeeded,完成磁盘维护
mPackageManagerService.performFstrimIfNeeded();
@Override
public void performFstrimIfNeeded() {
enforceSystemOrRoot("Only the system can request fstrim");
// Before everything else, see whether we need to fstrim.
try {
IStorageManager sm = PackageHelper.getStorageManager();
if (sm != null) {
boolean doTrim = false;
final long interval = Global.getLong(
mContext.getContentResolver(),
Global.FSTRIM_MANDATORY_INTERVAL,
DEFAULT_MANDATORY_FSTRIM_INTERVAL);
if (interval > 0) {
final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
if (timeSinceLast > interval) {
doTrim = true;
Slog.w(TAG, "No disk maintenance in " + timeSinceLast
+ "; running immediately");
}
}
if (doTrim) {
final boolean dexOptDialogShown;
synchronized (mPackages) {
dexOptDialogShown = mDexOptDialogShown;
}
if (!isFirstBoot() && dexOptDialogShown) {
try {
ActivityManager.getService().showBootMessage(
mContext.getResources().getString(
R.string.android_upgrading_fstrim), true);
} catch (RemoteException e) {
}
}
sm.runMaintenance();
}
} else {
Slog.e(TAG, "storageManager service unavailable!");
}
} catch (RemoteException e) {
// Can't happen; StorageManagerService is local
}
}
复制代码
- 第七步:调用systemReady,PKMS准备就绪
mPackageManagerService.systemReady();
复制代码
PKMS构造方法
image.pngAPK的扫描
PKMS的构造函数中调用了scanDirTracedLI方法来扫描某个目录的APK文件,Android10.0版本和其他低版本的扫描的路径是不一样的,PKMS主要扫描以下路径的APK信息,以下都属于系统app类别
/vendor/overlay
/product/overlay
/product_services/overlay
/odm/overlay
/oem/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/oem/priv-app
/product/priv-app
/product/app
/product_services/priv-app
/product_services/app
/product_services/priv-app
复制代码
APK扫描流程图
image.png在该流程中,可以看到AndroidManifest文件的解析后的所有信息存储在Package对象中。
APK扫描流程总结
- 第一步:扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容
- 第二步:解析清单文件到的信息由 Package 保存。从该类的成员变量可看出,和 Android四大组件相关的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此 activites 和 receivers等均声明为 ArrayList 。
APK的安装
APK的安装流程图(三大步骤)
image.pngAPK安装时序图
image.png具体步骤分析
点击一个apk后,会弹出安装界面,点击确定按钮后,会进入PackageInstallerActivity 的 bindUi() 中的mAlert点击事件, 弹出的安装界面底部显示的是一个diaglog,主要由bindUi构成,上面有 ”取消“ 和 ”安装“ 两个按钮,点击安装后 调用startInstall()进行安装:
private void bindUi() {
mAlert.setIcon(mAppSnippet.icon);
mAlert.setTitle(mAppSnippet.label);
mAlert.setView(R.layout.install_content_view);
mAlert.setButton(DialogInterface.BUTTON_POSITIVE,
getString(R.string.install),
(ignored, ignored2) -> {
if (mOk.isEnabled()) {
if (mSessionId != -1) {
startInstall 做的事情
mInstaller.setPermissionsResult(mSessionId, true);
finish();
} else {
startInstall(); // 进行APK安装 下面开始分析 }
}
}, null);
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(R.string.cancel),
(ignored, ignored2) -> {
// Cancel and finish
setResult(RESULT_CANCELED);
if (mSessionId != -1) {
//如果mSessionId存在,执行setPermissionsResult()完成取消安装
mInstaller.setPermissionsResult(mSessionId, false);
}
finish();
}, null);
setupAlert();
mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);
}
复制代码
startInstall方法组装了一个Intent,并跳转到 InstallInstalling 这个Activity,并关闭掉当前的PackageInstallerActivity。InstallInstalling主要用于向包管理器发送包的信息并处理包管理的回调:
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);
// 设置Intent中的class为 InstallInstalling,用来进行Activity跳转
// class InstallInstalling extends AlertActivity 下面会分析 InstallInstalling Activity
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);
finish();
}
复制代码
启动 InstallInstalling,进入onCreate, 重点是看onCreate函数中的六步:
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ApplicationInfo appInfo = getIntent()
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = getIntent().getData();
if ("package".equals(mPackageURI.getScheme())) {
try {
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
//根据mPackageURI创建一个对应的File
final File sourceFile = new File(mPackageURI.getPath()); PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo,
sourceFile);
mAlert.setIcon(as.icon);
mAlert.setTitle(as.label);
mAlert.setView(R.layout.install_content_view);
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(R.string.cancel),
(ignored, ignored2) -> {
if (mInstallingTask != null) {
mInstallingTask.cancel(true);
}
if (mSessionId > 0) {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
mSessionId = 0;
}
setResult(RESULT_CANCELED);
finish();
}, null);
setupAlert();
requireViewById(R.id.installing).setVisibility(View.VISIBLE);
// 第一步.如果savedInstanceState不为null,获取此前保存的mSessionId和 mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件id
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);
// Reregister for result; might instantly call back if result was
delivered while
// activity was destroyed
try {
// 第二步.根据mInstallId向InstallEventReceiver注册一个观察者,
launchFinishBasedOnResult会接收到安装事件的回调, //无论安装成功或者失败都会关闭当前的Activity(InstallInstalling)。如果
savedInstanceState为null,代码的逻辑也是类似的 InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
// Does not happen
}
} else {
// 第三步.创建SessionParams,它用来代表安装会话的参数,组装params
PackageInstaller.SessionParams params = new
PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setInstallAsInstantApp(false);
params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
params.setOriginatingUri(getIntent()
.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
UID_UNKNOWN));
params.setInstallerPackageName(getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME));
params.setInstallReason(PackageManager.INSTALL_REASON_USER);
// 第四步.根据mPackageUri对包(APK)进行轻量级的解析,并将解析的参数赋值给 SessionParams
File file = new File(mPackageURI.getPath());
try {
PackageParser.PackageLite pkg =
PackageParser.parsePackageLite(file, 0);
params.setAppPackageName(pkg.packageName);
params.setInstallLocation(pkg.installLocation);
params.setSize(
PackageHelper.calculateInstalledSize(pkg, false,
params.abiOverride));
} catch (PackageParser.PackageParserException e) {
Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only
params.setSize(file.length());
} catch (IOException e) {
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only
params.setSize(file.length());
apk size.");
apk size.");
}
try {
// 第五步.向InstallEventReceiver注册一个观察者返回一个新的mInstallId, //其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并
回调给EventResultPersister。
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
null);
}
try {
// 第六步.PackageInstaller的createSession方法内部会通过
IPackageInstaller与PackageInstallerService进行进程间通信, //最终调用的是PackageInstallerService的createSession方法来创建并返回
mSessionId
mSessionId =
getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
null);
}
}
mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
mSessionCallback = new InstallSessionCallback();
}
}
复制代码
以上第六步是重点 PackageInstaller 的 createSession()内部会通过IPackageInstaller与 PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法 来创建并返回mSessionId。
InstallInstalling.onResume方法中,调用onPostExecute()方法,将APK的信息通过IO流的形式写入到PackageInstaller.Session中
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller(); // 获取sessionInfo
PackageInstaller.SessionInfo sessionInfo =
installer.getSessionInfo(mSessionId);
if (sessionInfo != null && !sessionInfo.isActive()) {
// 最终执行onPostExecute() 下面来分析
// 创建内部类InstallingAsyncTask的对象,调用execute(),最终进入
onPostExecute()
} }
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
} else {
// we will receive a broadcast when the install is finished
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
复制代码
Installinstalling.InstallingAsyncTask : 关注第一步和第二步
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;
// 第一步: doInBackground()会根据包(APK)的Uri,将APK的信息通过IO流的形式写入到 PackageInstaller.Session中
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
session =
getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
return null;
}
session.setStagingProgress(0);
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) {
int numRead = in.read(buffer);
if (numRead == -1) {
session.fsync(out);
break;
}
} }
if (isCancelled()) {
session.close();
break; }
//将APK的信息通过IO流的形式写入到PackageInstaller.Session中 out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float)
session.addProgress(fraction);
} }
return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);
session.close();
return null;
} finally {
sizeBytes);
} }
synchronized (this) {
isDone = true;
notifyAll();
}
// 第二步:最后在onPostExecute()中 调用PackageInstaller.Session的commit方法,进行 安装
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(getPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// commit 下面会分析
// 调用PackageInstaller.Session的commit方法,进行安装 session.commit(pendingIntent.getIntentSender()); mCancelButton.setEnabled(false); setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
复制代码
PackageInstaller的commit()
[PackageInstaller.java] commit
public void commit(@NonNull IntentSender statusReceiver) {
try {
// mSession的类型为IPackageInstallerSession,这说明要通过
IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit 方法,这样代码逻辑就到了Java框架层的。
// 调用IPackageInstallerSession的commit方法, 跨进程调用到 PackageInstallerSession.commit()
mSession.commit(statusReceiver, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
if (mIsPerfLockAcquired && mPerfBoostInstall != null) {
mPerfBoostInstall.perfLockRelease();
mIsPerfLockAcquired = false;
}
...
// 调用markAsCommitted()
if (!markAsCommitted(statusReceiver, forTransfer)) {
return; }
...
// 向Handler发送一个类型为MSG_COMMIT的消息 ,下面会分析
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
复制代码
MSG_COMMIT在handler中进行处理,进入handleCommit()
public boolean handleMessage(Message msg) {
switch (msg.what) {
} }
case MSG_COMMIT:
handleCommit();
break;
private void handleCommit() {
List<PackageInstallerSession> childSessions = getChildSessions();
try {
synchronized (mLock) {
//最终调用installStage(),进入PKMS
commitNonStagedLocked(childSessions);
}
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
Slog.e(TAG, "Commit of session " + sessionId + " failed: " +
completeMsg);
destroyInternal();
dispatchSessionFinished(e.error, completeMsg, null);
}
}
复制代码
最终调用 mPm.installStage(),进入PKMS 【经过千辛万苦,终于要进入PKMS了】
private void commitNonStagedLocked(...)throws PackageManagerException {
if (isMultiPackage()) {
...
mPm.installStage(activeChildSessions); // 【同学们注意】跨越进程 进入 PKMS.installStage了
} else {
mPm.installStage(committingSession);
} }
复制代码
PKMS.installStage
[PackageManagerService.java]
void installStage(ActiveInstallSession activeInstallSession) {
if (DEBUG_INSTANT) {
if ((activeInstallSession.getSessionParams().installFlags
& PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " +
activeInstallSession.getPackageName());
}
}
// 第一步.创建了类型为INIT_COPY的消息
final Message msg = mHandler.obtainMessage(INIT_COPY);
// 第二步.创建InstallParams,它对应于包的安装数据
final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(pa
rams));
msg.obj = params;
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));
// 第三步.将InstallParams通过消息发送出去。
mHandler.sendMessage(msg);
}
对INIT_COPY的消息的处理 [PackageManagerService.java]
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
} }
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params)); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
// 执行APK拷贝动作,这里会执行到 final void startCopy() params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break; }
[PKMS.HandlerParams]
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); handleStartCopy();
handleReturnCode(); // 调用到下面 handleReturnCode
}
[PKMS.MultiPackageInstallParams]
void handleReturnCode() {
if (mVerificationCompleted && mEnableRollbackCompleted) {
.....
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = mArgs.copyApk(); // 下面会说到 copyApk
}
..... }
}
复制代码
APK 拷贝方法调用步骤如下:
PKMS
copyApk()
doCopyApk()
PackageManagerServiceUtils
copyPacakge()
copyFile()
复制代码
安装的原理
安装其实就是把apk文件copy到对应的目录
-
data/app/包名/,安装是吧apk文件复制到此目录,可以将文件取出并安装,和我们本身的apk是一样的,用该apk安装可能会遇到问题:用该命令 adb install -t
<apk>
来安装 -
data/data/包名/,开辟存放应用程序的文件数据的文件夹,包括我们的so库,缓存文件,oat文件等。
注意:开机的时候,如果配置了odex优化,会生成上面的oat文件内容,后面手机重启后不会重复进行优化,除非系统升级或者恢复出厂设置等操作。
- 将apk中的dex文件安装到data/dalvik-cach目录下(dex文件时dalvik虚拟机的可执行文件)
PKMS之权限扫描
PackageManagerService中执行systemReady()以后,需要对/system/etc/permissions中各种xml进行扫描,进行相应的权限存储,供之后权限管理使用。
PackageManagerService执行systemReady()时,通过SystemConfig的readPermissionsFromXml()来扫描读取 /system/etc/permissions中的xml文件,包括platform.xml和系统支持的各种硬件模块的 feature主要工作:
PKMS权限扫描流程图
image.png静默安装
// 如果想实现,静默安装,就需要设置好UID,只有设置这个UID后,才有安装的权限
// 但是这个UID必须要求有系统的[签名], 而这个系统的[签名]是属于各大手机厂商的机密,也 意味着非常的坑爹
// 如果是系统厂商要做这种静默安装, 那就是非常容易的事情, 因为系统厂商可以轻而易举的拿 到 系统的[签名]
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);
mSettings.addSharedUserLPw("android.uid.se", SE_UID,
ApplicationInfo.FLAG_SYSTEM,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
ApplicationInfo.FLAG_SYSTEM,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
复制代码
requestPermissions源码流程解析
Google在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限(需要动态的申请并得到用户的授权才能使用)。
核心方法简介:
//检查权限
checkSelfPermission(@NonNull String permission)
//申请权限
requestPermissions(@NonNull String[] permissions, int requestCode)
//处理结果回调
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults)
//是否需要显示UI界面提示用户为什么需要这个权限
shouldShowRequestPermissionRationale(@NonNull String permission)
复制代码
权限源码申请流程总结:
-
第一步:MainActivity 调用 requestPermissions 进行动态权限申请;
-
第二步:requestPermissions函数通过隐式意图,激活PackageInstaller的GrantPermissionsActivity界 面,让用户选择是否授权;
-
第三步:经过PKMS把相关信息传递给PermissionManagerService处理;
-
第四步:PermissionManagerService处理结束后回调给---->PKMS中的onPermissionGranted方法把处理结果返回;
-
第五步:PKMS通知过程中权限变化,并调用writeRuntimePermissionsForUserLPr函数让PackageManager的settings记录下相关授权信息。
面试题
-
为什么手机启动那么耗时
点击开机键,固定的地方启动开机动画,启动linux驱动,然后启动init进程(用户态第一个进程),init进程启动zogyte进程,zogyte启动SystemServer,SystemServer的main函数启动各种服务,PMS中的构造函数有五个阶段耗时,五个阶段后还会进行dex优化。
-
startActivity MainActivity跳转到LoginActivity设置android:launcMode="singleTask",这个singleTask是什么时候被解析的? PKMS提前就进行加载了,存放在Package中了,Package里面有所有apk的配置信息,不需要再解析。
-
静态广播是什么时候注册的?
手机开机的时候,PKMS构造函数, PKMS扫描进来Package,再进行注册
-
开机的时候,不会把apk重新安装一遍,那样太恐怖了,在ota(系统升级)的时候会进行重新安装一遍。
-
SystemServer.run()方法简要介绍
- startBootstrapServices() 引导服务,AMS,PKMS,电源管理等等
- startCoreServices() 核心服务
- startOtherServices() 其他服务
-
安装新的apk过程,何时进行配置文件的获取(扫描),PackageInstallerActivity的onCreate方法中processPackageUri,该方法只是进行权限等内容的扫描,不会全部扫描,执行安装方法之前,真正进行扫描的方法是在PKMS.installPackageLI方法
//PackageInstallerActivity.java 界面弹出框 protected void onCreate(Bundle icicle) { getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); super.onCreate(null); // 初始化安装需要用到的对象 mPm = getPackageManager(); mIpm = AppGlobals.getPackageManager(); mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE); mInstaller = mPm.getPackageInstaller(); mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); // 根据Uri的Scheme做不同的处理,这里面进行扫描。 boolean wasSetUp = processPackageUri(packageUri); if (!wasSetUp) { return; } // 显示安装界面 bindUi(); // 检查是否允许安装包,如果允许则启动安装。如果不允许显示适当的对话框 checkIfAllowedAndInitiateInstall(); } 复制代码
主要做了对象的初始化,解析 Uri 的 Scheme,初始化界面,安装包检查等等工作,接着查看一下 processPackageUri 方法,这里只是获取一些权限,名字,icon等等,没有进行全部解析AndroidManifest.xml文件,各个厂商可以自己定制。
真正进行全部扫描的方法是在PKMS.installPackageLI。
网友评论