当前位置:   article > 正文

android 9.0 adb 应用安装过程_restoreatinstallforuser

restoreatinstallforuser

引言
最近手上有银联商务招标的需求,涉及到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);
  • 1
  • 2

}

调用到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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

通过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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

调用到runInstall()方法,主要流程是doCreateSession(),doWriteSplit(),doCommitSession()这三个方法

901      private int runInstall() throws RemoteException {
  • 1

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;
  • 1

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 {
  • 1
  • 2
  • 3

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");
}
  • 1
  • 2
  • 3
  • 4

这里生成/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);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

文件路径是data/system/install_sessions.xml,里面的内容:

*******声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】

推荐阅读
相关标签