赞
踩
引言
最近手上有银联商务招标的需求,涉及到apk的验签策略,梳理一遍adb install的流程。
每次看完源码,做完需求,后面就慢慢忘记代码流程了,遂写成博客记录下来。
流程图
开始写博客,不太会使用Flowchart流程图,从博友那借用了一张。
c++到java的流程没看懂,流程图有点对不上android9.x的流程,将就着看吧。
出处:https://blog.csdn.net/chishi199433/article/details/103925833
(侵权必删)
adb inatsll ***.apk 命令对应的代码在/system/core/adb/commandline.cpp里面
int adb_commandline(int argc, const char** argv) {
…
//adb其他命令,pull,push,shell,ls…
…
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);
}
}
调用到install_app_legacy()函数
static int uninstall_app_legacy(int argc, const char** argv) {
…
…
/* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
return pm_command(argc, argv);
}
调用到pm_command()函数
2045 static int pm_command(int argc, const char** argv) {
2046 std::string cmd = “pm”;
2047
2048 while (argc-- > 0) {
2049 cmd += " " + escape_arg(*argv++);
2050 }
2051
2052 return send_shell_command(cmd, false);
2053 }
调用到send_shell_command()函数,看了下里面的逻辑,没看懂怎么调用到java层。
不死心想要弄清楚c++到java的流程,从java层开始逆向分析。
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) {
+ Thread.dumpStack();
(new PackageManagerShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
通过Thread.dumpStack()打印调用方法栈,编译,push Service.jar之后查看log
03-04 16:40:27.204 907 1021 W System.err: java.lang.Exception: Stack trace
03-04 16:40:27.205 907 1021 W System.err: at java.lang.Thread.dumpStack(Thread.java:1348)
03-04 16:40:27.205 907 1021 W System.err: at com.android.server.pm.PackageManagerService.onShellCommand(PackageManagerService.java:21781)
03-04 16:40:27.205 907 1021 W System.err: at android.os.Binder.shellCommand(Binder.java:634)
03-04 16:40:27.205 907 1021 W System.err: at android.os.Binder.onTransact(Binder.java:532)
03-04 16:40:27.205 907 1021 W System.err: at android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:2796)
03-04 16:40:27.205 907 1021 W System.err: at com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:3964)
03-04 16:40:27.205 907 1021 W System.err: at android.os.Binder.execTransact(Binder.java:731)
看到熟悉的android.os.Binder和onTransact(),恍然大悟,原来是用的Binder机制,不懂的同学建议学习Binder的相关知识
继续从PackageManagerService.java的onShellCommand()方法开始分析,exec()调用的是父类ShellCommand.java的方法
frameworks/base/core/java/android/os/ShellCommand.java
79 public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
80 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
81 String cmd;
82 int start;
83 if (args != null && args.length > 0) {
84 cmd = args[0];
85 start = 1;
86 } else {
87 cmd = null;
88 start = 0;
89 }
90 init(target, in, out, err, args, callback, start);
91 mCmd = cmd;
92 mResultReceiver = resultReceiver;
93 …
…
101 int res = -1;
102 try {
103 res = onCommand(mCmd);
104 if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
105 } catch (SecurityException e) {
106 PrintWriter eout = getErrPrintWriter();
107 eout.println("Security exception: " + e.getMessage());
108 eout.println();
109 e.printStackTrace(eout);
110 } catch (Throwable e) {
111 …
…
119 } finally {
120 …
…
130 }
131 }
132 if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
133 return res;
134 }
调用到onCommand()方法
public abstract int onCommand(String cmd);
1
看到abstract字段,就知道是子类继承,重写方法
frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@Override public int onCommand(String cmd) { if (cmd == null) { return handleDefaultCommands(cmd); } final PrintWriter pw = getOutPrintWriter(); try { switch(cmd) { .......... .......... case "install": return runInstall(); .......... .......... } } catch (RemoteException e) { pw.println("Remote exception: " + e); } return -1; }
调用到runInstall()方法,主要流程是doCreateSession(),doWriteSplit(),doCommitSession()这三个方法
901 private int runInstall() throws RemoteException {
902 final PrintWriter pw = getOutPrintWriter();
903 final InstallParams params = makeInstallParams();
904 final String inPath = getNextArg();
905
906 setParamsSize(params, inPath);
//创建sessionId
907 final int sessionId = doCreateSession(params.sessionParams,
908 params.installerPackageName, params.userId);
909 boolean abandonSession = true;
910 try {
911 if (inPath == null && params.sessionParams.sizeBytes == -1) {
912 pw.println(“Error: must either specify a package size or an APK file”);
913 return 1;
914 }
915 if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, “base.apk”,
916 false /logSuccess/) != PackageInstaller.STATUS_SUCCESS) {
917 return 1;
918 }
919 if (doCommitSession(sessionId, false /logSuccess/)
920 != PackageInstaller.STATUS_SUCCESS) {
921 return 1;
922 }
923 abandonSession = false;
924 pw.println(“Success”);
925 return 0;
926 } finally {
927 if (abandonSession) {
928 try {
929 doAbandonSession(sessionId, false /logSuccess/);
930 } catch (Exception ignore) {
931 }
932 }
933 }
934 }
doCreateSession()
doCreateSession()方法去创建PackageInstallerSession对象,返回sessionId。
final IPackageManager mInterface;
2406 private int doCreateSession(SessionParams params, String installerPackageName, int userId)
2407 throws RemoteException {
2408 userId = translateUserId(userId, true /allowAll/, “runInstallCreate”);
2409 if (userId == UserHandle.USER_ALL) {
2410 userId = UserHandle.USER_SYSTEM;
2411 params.installFlags |= PackageManager.INSTALL_ALL_USERS;
2412 }
2413
2414 final int sessionId = mInterface.getPackageInstaller()
2415 .createSession(params, installerPackageName, userId);
2416 return sessionId;
2417 }
看到IPackageManager mInterface,Binder机制,找IPackageManager 的实现类
/frameworks/base/core/java/android/app/ApplicationPackageManager.java
2454 @Override
2455 public PackageInstaller getPackageInstaller() {
2456 synchronized (mLock) {
2457 if (mInstaller == null) {
2458 try {
2459 mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
2460 mContext.getPackageName(), mContext.getUserId());
2461 } catch (RemoteException e) {
2462 throw e.rethrowFromSystemServer();
2463 }
2464 }
2465 return mInstaller;
2466 }
2467 }
mInterface.getPackageInstaller()返回PackageInstaller对象
/frameworks/base/core/java/android/content/pm/PackageInstaller.java
private final IPackageInstaller mInstaller;
public int createSession(@NonNull SessionParams params) throws IOException {
326 try {
327 final String installerPackage;
328 if (params.installerPackageName == null) {
329 installerPackage = mInstallerPackageName;
330 } else {
331 installerPackage = params.installerPackageName;
332 }
333
334 return mInstaller.createSession(params, installerPackage, mUserId);
335 } catch (RuntimeException e) {
336 ExceptionUtils.maybeUnwrapIOException(e);
337 throw e;
338 } catch (RemoteException e) {
339 throw e.rethrowFromSystemServer();
340 }
341 }
看到IPackageInstaller mInstaller,Binder机制,找IPackageInstaller 的实现类
/frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
401 @Override
402 public int createSession(SessionParams params, String installerPackageName, int userId) {
403 try {
404 return createSessionInternal(params, installerPackageName, userId);
405 } catch (IOException e) {
406 throw ExceptionUtils.wrap(e);
407 }
408 }
409
410 private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
411 throws IOException {
412 …
//权限检查
//根据调用者的UID调整installFlags
//安装位置处理,不能安装在外部存储
//设置app图标大小
440 …
508 final int sessionId;
509 final PackageInstallerSession session;
510 synchronized (mSessions) {
511 // Sanity check that installer isn’t going crazy
//检查mSessions数组里面PackageInstallerSession对象的数量,最大数量1024
512 final int activeCount = getSessionCount(mSessions, callingUid);
513 if (activeCount >= MAX_ACTIVE_SESSIONS) {
514 throw new IllegalStateException(
515 "Too many active sessions for UID " + callingUid);
516 }
517 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
518 if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
519 throw new IllegalStateException(
520 "Too many historical sessions for UID " + callingUid);
521 }
//生成sessionId
523 sessionId = allocateSessionIdLocked();
524 }
525
526 final long createdMillis = System.currentTimeMillis();
527 // We’re staging to exactly one location
528 File stageDir = null;
529 String stageCid = null;
530 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
531 final boolean isInstant =
532 (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
//data下面新建vmdl0123456789.tmp临时目录
533 stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
534 } else {
535 stageCid = buildExternalStageCid(sessionId);
536 }
537 //构建PackageInstallerSession对象
538 session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
539 mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
540 params, createdMillis, stageDir, stageCid, false, false);
541
542 synchronized (mSessions) {
//使用数组来存放sessionId和PackageInstallerSession对象
543 mSessions.put(sessionId, session);
544 }
545 //创建成功回调,回调给实现了IPackageInstallerCallback接口的类
546 mCallbacks.notifySessionCreated(session.sessionId, session.userId);
547 writeSessionsAsync();
548 return sessionId;
549 }
allocateSessionIdLocked()方法里面去生成sessionId,我们可以写成自己想要sessionId。
private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
return new File(stagingDir, "vmdl" + sessionId + ".tmp");
}
这里生成/data/app/vmdl01234567890.tmp文件夹,用来存放临时apk文件
再来看writeSessionsAsync()方法,将PackageInstallerSession信息写入mSessionsFile文件
mSessionsFile = new AtomicFile( new File(Environment.getDataSystemDirectory(), "install_sessions.xml"), "package-session"); mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions"); mSessionsDir.mkdirs(); .......... .......... private void writeSessionsAsync() { IoThread.getHandler().post(new Runnable() { @Override public void run() { synchronized (mSessions) { writeSessionsLocked(); } } }); } ......... ......... @GuardedBy("mSessions") private void writeSessionsLocked() { if (LOGD) Slog.v(TAG, "writeSessionsLocked()"); FileOutputStream fos = null; try { fos = mSessionsFile.startWrite(); XmlSerializer out = new FastXmlSerializer(); out.setOutput(fos, StandardCharsets.UTF_8.name()); out.startDocument(null, true); out.startTag(null, TAG_SESSIONS); final int size = mSessions.size(); for (int i = 0; i < size; i++) { final PackageInstallerSession session = mSessions.valueAt(i); session.write(out, mSessionsDir); } out.endTag(null, TAG_SESSIONS); out.endDocument(); mSessionsFile.finishWrite(fos); } catch (IOException e) { if (fos != null) { mSessionsFile.failWrite(fos); } } }
文件路径是data/system/install_sessions.xml,里面的内容:
*******声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。