概述
PackageManagerService(以下简称 PMS)是一个常用的系统服务,主要负责系统中的 Package 的管理,应用程序的安装、卸载、查询等相关功能。其相关类图如下
相关类说明
- IPackageManager
定义了服务端和客户端通信的业务函数,还定义了内部类 Stub ,该类从 Binder 派生并实现了 IPackageManager 接口 - PackageManagerService
继承自 IPackageManager.Stub 类,由于 Stub 类从 Binder 派生,因此 PackageManagerService 将作为服务端参与 Binder 通信 - Stub
定义了一个内部类 Proxy ,该类有一个 IBinder 类型(实际类型为 BinderProxy )的成员变量 mRemote ,根据 Binder 详解 中介绍的 Binder 系统的知识,mRemote 用于和服务端 PackageManagerService 通信 - ApplicationPackageManager
承自 PackageManager 类。它并没有直接参与 Binder 通信,而是通过 mPM 成员变量指向一个 IPackageManager.Stub.Proxy 类型的对象。
注:IPackageManager 在 Android Studio 中可能找不到,因为他是一个 AIDL 处理后的文件,这里附上相关的 IPackageManager.aidl 文件
PMS 服务启动
分析 PMS 之前我们先来看下这玩意是在哪里启动的。
我们都知道系统启动的时候会调用 SystemServer 的 main 函数。
注释已经说明了,这个 main 函数是通过 zygote 调用的,这块的调用链涉及到了进程启动相关,此处先不多说。看到 main 创建了一个自己然后调用 run 方法。
可以看到在 run 方法中系统将服务类型按照级别分为了三大类,引导服务、内核服务、其他服务,而 PMS 的启动就在引导服务中启动。
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
// Start services.
try {
//系统引导服务
startBootstrapServices();
//内核服务
startCoreServices();
//其他服务
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
}
private void startBootstrapServices() {
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
//标注①
mPackageManager = mSystemContext.getPackageManager();
}
我们进入 PackageManagerService 的 main 方法继续追踪。
可以看到在 main 方法中也是 new 了一把自己。然后将服务添加的 ServiceManager 中进行管理。到这,PMS 服务就启动完成了。
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
}
这里在额外看一下 PackageManager 的创建。上面 标注① 出获取了 PackageManager ,我们就以此为入口看下。mSystemContext 为 Content 的一个实现类,可以直接搜 ContextImpl
。
可以看到和上面的类图完美的对应上了,这里拿到系统提供的 PM,然后创建一个 ApplicationPackageManager 持有这个 pm 去和系统服务进行交互。
class ContextImpl extends Context {
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
}
注:Android 系统启动慢的原因就是在启动 PMS 的时候,需要执行扫描文件夹、处理权限、安装系统应用(文件的解压与copy)等比较耗时的操作。
应用程序(APK)安装
有界面安装
我们下载的安装包都是一个 .apk 文件,当我们点击该文件的时候,会启动系统的一个安装 apk 的应用,该应用是系统应用,在系统启动时就已经安装成功了。这里附上 PackageInstaller.apk 源码
首先这个 Intent 会启动 InstallStart ,在这里做一些校验后就跳转到 PackageInstallerActivity 进行确认安装后,进入 InstallInstalling 界面进行安装。
可以看到在 AndroidManifest.xml 中对外暴露了 InstallStart。
<activity android:name=".InstallStart"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="package" />
<data android:scheme="content" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
安装界面调用流程
public class InstallStart extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
Intent nextActivity = new Intent(intent);
......
nextActivity.setClass(this, PackageInstallerActivity.class);
......
if (nextActivity != null) {
startActivity(nextActivity);
}
finish();
}
}
public class PackageInstallerActivity extends OverlayTouchActivity implements OnClickListener {
public void onClick(View v) {
if (v == mOk) {
if (mOk.isEnabled()) {
if (mOkCanInstall || mScrollView == null) {
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);
finish();
} else {
//确认安装
startInstall();
}
} else {
mScrollView.pageScroll(View.FOCUS_DOWN);
}
}
} else if (v == mCancel) {
// Cancel and finish
setResult(RESULT_CANCELED);
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, false);
}
finish();
}
}
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
......
newIntent.setClass(this, InstallInstalling.class);
......
startActivity(newIntent);
finish();
}
}
public class InstallInstalling extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.installFlags = PackageManager.INSTALL_FULL_APP;
......
try {
//标注②
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
}
}
上面标注②中获取了 PackageInstaller 执行真正的安装
public class ApplicationPackageManager extends PackageManager {
@Override
public PackageInstaller getPackageInstaller() {
synchronized (mLock) {
if (mInstaller == null) {
try {
mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
mContext.getPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return mInstaller;
}
}
}
public class PackageInstaller {
//标注③
private final IPackageInstaller mInstaller;
public int createSession(@NonNull SessionParams params) throws IOException {
try {
final String installerPackage;
if (params.installerPackageName == null) {
installerPackage = mInstallerPackageName;
} else {
installerPackage = params.installerPackageName;
}
return mInstaller.createSession(params, installerPackage, mUserId);
} catch (RuntimeException e) {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
上面标注③ 中的 IPackageInstaller 为 PackageInstallerService 的 Binder 对象,看到这里是不发现,系统服务将 Binder 通信用的是淋漓尽致啊。
这里安装完成后通过 Binder 和 Handler 进行回调。
public class PackageInstallerService extends IPackageInstaller.Stub {
@Override
public int createSession(SessionParams params, String installerPackageName, int userId) {
try {
return createSessionInternal(params, installerPackageName, userId);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
}
private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
throws IOException {
final int callingUid = Binder.getCallingUid();
mPermissionManager.enforceCrossUserPermission(
callingUid, userId, true, true, "createSession");
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
throw new SecurityException("User restriction prevents installing");
}
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
params.installFlags |= PackageManager.INSTALL_FROM_ADB;
} else {
// Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
// caller.
if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) !=
PackageManager.PERMISSION_GRANTED) {
mAppOps.checkPackage(callingUid, installerPackageName);
}
params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
&& !mPm.isCallerVerifier(callingUid)) {
params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
}
}
// Only system components can circumvent runtime permissions when installing.
if ((params.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");
}
if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
|| (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
throw new IllegalArgumentException(
"New installs into ASEC containers no longer supported");
}
// Defensively resize giant app icons
if (params.appIcon != null) {
final ActivityManager am = (ActivityManager) mContext.getSystemService(
Context.ACTIVITY_SERVICE);
final int iconSize = am.getLauncherLargeIconSize();
if ((params.appIcon.getWidth() > iconSize * 2)
|| (params.appIcon.getHeight() > iconSize * 2)) {
params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
true);
}
}
switch (params.mode) {
case SessionParams.MODE_FULL_INSTALL:
case SessionParams.MODE_INHERIT_EXISTING:
break;
default:
throw new IllegalArgumentException("Invalid install mode: " + params.mode);
}
// If caller requested explicit location, sanity check it, otherwise
// resolve the best internal or adopted location.
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
if (!PackageHelper.fitsOnInternal(mContext, params)) {
throw new IOException("No suitable internal storage available");
}
} else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
if (!PackageHelper.fitsOnExternal(mContext, params)) {
throw new IOException("No suitable external storage available");
}
} else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
// For now, installs to adopted media are treated as internal from
// an install flag point-of-view.
params.setInstallFlagsInternal();
} else {
// For now, installs to adopted media are treated as internal from
// an install flag point-of-view.
params.setInstallFlagsInternal();
// Resolve best location for install, based on combination of
// requested install flags, delta size, and manifest settings.
final long ident = Binder.clearCallingIdentity();
try {
params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
// Sanity check that installer isn't going crazy
final int activeCount = getSessionCount(mSessions, callingUid);
if (activeCount >= MAX_ACTIVE_SESSIONS) {
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
throw new IllegalStateException(
"Too many historical sessions for UID " + callingUid);
}
sessionId = allocateSessionIdLocked();
}
final long createdMillis = System.currentTimeMillis();
// We're staging to exactly one location
File stageDir = null;
String stageCid = null;
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
final boolean isInstant =
(params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
} else {
stageCid = buildExternalStageCid(sessionId);
}
session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
params, createdMillis, stageDir, stageCid, false, false);
synchronized (mSessions) {
mSessions.put(sessionId, session);
}
mCallbacks.notifySessionCreated(session.sessionId, session.userId);
writeSessionsAsync();
return sessionId;
}
}
无界面安装
上面说的有界面安装是正常的安装方式,可以让用户感知的。然而还有一种比较流氓的方式,就是静默安装。用户无感知,这个应用就被安装成功了。
这种方式就是通过 adb 命令进行安装 adb install
这个命令我们可以在 commandline.cpp 中找到。可以看到通过命令匹配 执行 install_app 函数。与之相应的还有 adb uninstall 命令
int adb_commandline(int argc, const char** argv) {
......
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return syntax_error("install requires an argument");
if (_use_legacy_install()) {
return install_app_legacy(argc, argv);
}
return install_app(argc, argv);
}
......
else if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) return syntax_error("uninstall requires an argument");
if (_use_legacy_install()) {
return uninstall_app_legacy(argc, argv);
}
return uninstall_app(argc, argv);
}
......
}
static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
......
result = pm_command(transport, serial, argc, argv);
......
return result;
}
static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) {
std::string cmd = "pm";
while (argc-- > 0) {
cmd += " " + escape_arg(*argv++);
}
return send_shell_command(transport, serial, cmd, false);
}
顺着调用栈走下去发现最终执行了 pm 命令。而这个命令会执行一个 pm.jar 文件,该 jar 包是通过 Pm.java 打包而成。
命令执行后会调用 Pm 的 main 函数。顺着调用往下走,最终发现还是调用了 PackageInstallerService 的 createSession 函数。殊途同归,和有界面安装走入相同的流程了。
public final class Pm {
public static void main(String[] args) {
int exitCode = 1;
try {
exitCode = new Pm().run(args);
} catch (Exception e) {
Log.e(TAG, "Error", e);
System.err.println("Error: " + e);
if (e instanceof RemoteException) {
System.err.println(PM_NOT_RUNNING_ERR);
}
}
System.exit(exitCode);
}
public int run(String[] args) throws RemoteException {
boolean validCommand = false;
if (args.length < 1) {
return showUsage();
}
mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (mPm == null) {
System.err.println(PM_NOT_RUNNING_ERR);
return 1;
}
mInstaller = mPm.getPackageInstaller();
......
if ("install".equals(op)) {
return runInstall();
}
......
if ("uninstall".equals(op)) {
return runUninstall();
}
......
}
private int runInstall() throws RemoteException {
......
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
......
}
private int doCreateSession(SessionParams params, String installerPackageName, int userId)
throws RemoteException {
userId = translateUserId(userId, "runInstallCreate");
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
params.installFlags |= PackageManager.INSTALL_ALL_USERS;
}
final int sessionId = mInstaller.createSession(params, installerPackageName, userId);
return sessionId;
}
}
APK 安装原理
至此对于 PMS 的启动,和 APK 文件的两种安装方式我们都分析完了,下面对结合两种安装方式总结一下
对于 Android 系统安装 APK 应用,就是将 APK 文件解压,把相应的文件 copy 到相应的目录中即可。
- data/app/package_name
安装时将 apk 文件复制到此目录,可以将文件取出并安装 - data/data/package_name
开辟存放应用程序的文件数据的文件夹,包括我们的 so 库、缓存文件等 - data/dalvik-cache
将 apk 解压出的 dex 文件复制到此目录