Android 9 平台
安装应用一般有三种方式:
命令, PackageManager.installPackage(), 发Intent方式
1.命令安装
之前是用adb shell pm ...命令
现在是用adb shell cmd package ...命令,
也可用adb install 命令安装应用。
cmd package命令通过binder的shell cmd 调用
frameworks/native/cmds/cmd/cmd.cpp
IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
参数service即传入的package服务,经过Binder的一些传递(CPP 通过binder调用JAVA Binder服务)最终调用onShellCommand()
frameworks/base/core/java/android/os/Binder.java
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
......{
onShellCommand(in, out, err, args, callback, resultReceiver);
}
对用package来说,即调用到
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
(new PackageManagerShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
PackageManagerShellCommand.java 继承 ShellCommand.java,其exec()代码位于ShellCommand.java最后调到 onCommand(mCmd);
也即
frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java onCommand(String cmd)
对于install命令来说, 调用 runInstall()然后与PackageInstaller交互,CreateSession, commit
private int runInstall() throws RemoteException {
......
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
......
if (doCommitSession(sessionId, false /*logSuccess*/)
命令行安装大体流程
IBinder::shellCommand()/cmd.cpp --> .... --> onShellCommand()/PackageManagerService.java --> exec()/ShellCommand.java
--> onCommand()/PackageManagerShellCommand.java -->
runInstall()
+--> doCreateSession()
| +--> mInterface.getPackageInstaller().createSession(params, installerPackageName, userId);
+--> doCommitSession()
+--> new PackageInstaller.Session(mInterface.getPackageInstaller().openSession(sessionId));
+--> session.commit(receiver.getIntentSender())
2 PackageManager installPackage()
2.1 应用getPackageManager()
mContext.getPackageManager();
frameworks/base/core/java/android/content/ ContextWrapper.java
ContextWrapper extends Context
Context mBase;
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
Context.java
public abstract PackageManager getPackageManager();
最终实现
frameworks/base/core/java/android/app/ContextImpl.java
ContextImpl extends Context
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)); <--- ApplicationPackageManager()
}
return null;
}
即:
mContext.getPackageManager(); --> ApplicationPackageManager()
frameworks/base/core/java/android/app/ApplicationPackageManager.java
ApplicationPackageManager extends PackageManager
2.2 installPackage()
从Android 7开始
PackageManager.java installPackage()标注被 PackageInstaller 代替, 9.0里已找不到该接口.
PackageInstaller位置:
frameworks/base/core/java/android/content/pm/PackageManager.java
public abstract @NonNull PackageInstaller getPackageInstaller();
ApplicationPackageManager.java
public PackageInstaller getPackageInstaller() {
......
mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
mContext.getPackageName(), mContext.getUserId());
......
}
3 通过Intent安装新应用
示例: development/samples/ApiDemos/src/com/example/android/apis/content/InstallApk.java
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
...
startActivity(intent);
-->该intent接收者定义在
packages/apps/PackageInstaller/AndroidManifest.xml
<activity android:name=".InstallStart"
......
<action android:name="android.intent.action.INSTALL_PACKAGE"
-->然后会调用到
packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
--> 需要权限确认是 PackageInstallerActivity.class
-->
packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
--> startInstall() {
newIntent.setClass(this, InstallInstalling.class);
--> packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
onResume()
mStagingTask = new StagingAsyncTask();
mStagingTask.execute(getIntent().getData()); --> session.commit(pendingIntent.getIntentSender());
4 session.commit()
cmd package命令安装和点击安装最后都调到session.commit(),直接看commit(), 之前的create session创建会话略过
且只分析新安装, 不分析升级。
其最终的实现是在
frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
commit()
+--> MSG_COMMIT
+--> commitLocked()
+--> extractNativeLibraries()
+--> mPm.installStage()
+--> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+-> installStage()
+--> sendMessage INIT_COPY
case INIT_COPY:
+--> mBound connectToService() 检查是否bind了 DefaultContainerService 服务
+--> mPendingInstalls.add() 添加到Pending中排个队
+--> sendMessage MCS_BOUND
case MCS_BOUND:
+--> params.startCopy()
+--> handleStartCopy()
+--> 一大堆检查,错误处理,验证
+--> args.copyApk() --> 注4.1
+--> handleReturnCode()
+--> processPendingInstall()
+--> args.doPreInstall(res.returnCode);
+--> installPackageTracedLI(args, res);
+--> installPackageLI(args, res); --> 注4.2
+--> args.doPostInstall(res.returnCode, res.uid); --> 广播
+ 如果还有pending的,发个MCS_BOUND消息,这样loop处理下一个
注4.1:
copyApk()同样是调用DefaultContainerService的copyPackage()将应用的文件复制到/data/app 下。
如果应用中还有native的动态库,也会把包在apk文件中的动态库的文件提取出来。
执行完copyApk()后,安装的第一阶段的工作就完成了,应用安装到了/data/app目录下
注4.2:
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
......
PackageParser pp = new PackageParser();
......
// 1. 解析apk
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
...... // 2. 收集签名
PackageParser.collectCertificates(pkg, false /* skipVerify */);
...... // 3. 一大堆的检查
// Check if installing already existing package
...... permissions检查
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
...... // 4. 如果是升级,调用 replacePackageLIF() 否则 installNewPackageLIF()
if (replace) {
......
replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
installerPackageName, res, args.installReason);
} else {
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
..... // 5. performDexopt
if (performDexopt) {
......
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
dexoptOptions);
......
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
.......
PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
System.currentTimeMillis(), user); --> 扫描包信息, 解析AndroidManifest.xml等
updateSettingsLI(newPackage, installerPackageName, null, res, user);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
prepareAppDataAfterInstallLIF(newPackage); --> mInstaller.createAppData()
} else {
// Remove package from internal structures, but keep around any
// data that might have already existed
deletePackageLIF(pkgName, UserHandle.ALL, false, null,
PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
}
5. PMS初始化
startBootstrapServices() SystemServer.java --> PackageManagerService.main()
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// 1.
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
// 2.
m.enableSystemUserPackages();
// 3.
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
//4 .
ServiceManager.addService("package_native", pmn);
return m;
}
看似简单,即new PMS类和Native类,然后加入到ServiceManager服务中,但是注释1和注释3干的事也挺多的,之前用思维导图整理了下,可保存下来放大看看
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。