0%

app_process启动进程

app_process进程

  • 进程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    adb shell ps -A

    USER PID PPID VSZ RSS WCHAN ADDR S NAME
    u0_a143 17275 902 13818920 135244 futex_wait_queue_me 0 S com.example.myapplication2 //app
    u0_a143 17302 17275 10771080 2528 SyS_rt_sigsuspend 0 S sh //shell
    u0_a143 17304 17302 13006212 73728 do_sys_poll 0 S songpengfei // app_process进程

    # app -> shell -> app_process kill app ,一切皆亡
    # Xposed的原理就是 重新制作app_process,实现了对系统的接管
  • 原理

将Server端dex push到手机,利用app_process启动Sever端进程,Client和Server相互通信

  • 操作
    • Server端编译成dex(java - class - dex)
    • 将dex push到手机 或者放在app的assets目录下
    • 启动dex文件 push到手机可以直接用adb启动,如果是在app的assets目录下,需要先复制到sdcard,然后调用 system/bin/app_process
    • 启动client端

      app_process命令

      用途:

      通过app_process命令可以启动一个进程。系统的zygote和application都是通过这种方式启动的。

      命令:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

      app_process [vm-options] cmd-dir [options] start-class-name [main-options]

      # vm-options – VM 选项
      # cmd-dir –父目录 (/system/bin)
      # options –运行的参数 :
      # –zygote
      # –start-system-server
      # –application (api>=14)
      # –nice-name (api>=14)
      # start-class-name –包含main方法的主类 (com.android.commands.am.Am)
      # main-options –启动时候传递到main方法中的参数

      源码:

      /aosp/frameworks/base/cmds/app_process/app_main.cpp
      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
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      int main(int argc, char* const argv[])
      {
      if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
      argv_String.append("\"");
      argv_String.append(argv[i]);
      argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
      }

      AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
      // Process command line arguments
      // ignore argv[0]
      argc--;
      argv++;

      // Everything up to '--' or first non '-' arg goes to the vm.
      //
      // The first argument after the VM args is the "parent dir", which
      // is currently unused.
      //
      // After the parent dir, we expect one or more the following internal
      // arguments :
      //
      // --zygote : Start in zygote mode
      // --start-system-server : Start the system server.
      // --application : Start in application (stand alone, non zygote) mode.
      // --nice-name : The nice name for this process.
      //
      // For non zygote starts, these arguments will be followed by
      // the main class name. All remaining arguments are passed to
      // the main method of this class.
      //
      // For zygote starts, all remaining arguments are passed to the zygote.
      // main function.
      //
      // Note that we must copy argument string values since we will rewrite the
      // entire argument block when we apply the nice name to argv0.
      //
      // As an exception to the above rule, anything in "spaced commands"
      // goes to the vm even though it has a space in it.
      const char* spaced_commands[] = { "-cp", "-classpath" };
      // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
      bool known_command = false;

      int i;
      for (i = 0; i < argc; i++) {
      if (known_command == true) {
      runtime.addOption(strdup(argv[i]));
      // The static analyzer gets upset that we don't ever free the above
      // string. Since the allocation is from main, leaking it doesn't seem
      // problematic. NOLINTNEXTLINE
      ALOGV("app_process main add known option '%s'", argv[i]);
      known_command = false;
      continue;
      }

      for (int j = 0;
      j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
      ++j) {
      if (strcmp(argv[i], spaced_commands[j]) == 0) {
      known_command = true;
      ALOGV("app_process main found known command '%s'", argv[i]);
      }
      }

      if (argv[i][0] != '-') {
      break;
      }
      if (argv[i][1] == '-' && argv[i][2] == 0) {
      ++i; // Skip --.
      break;
      }

      runtime.addOption(strdup(argv[i]));
      // The static analyzer gets upset that we don't ever free the above
      // string. Since the allocation is from main, leaking it doesn't seem
      // problematic. NOLINTNEXTLINE
      ALOGV("app_process main add option '%s'", argv[i]);
      }

      // Parse runtime arguments. Stop at first unrecognized option.
      bool zygote = false;
      bool startSystemServer = false;
      bool application = false;
      String8 niceName;
      String8 className;

      ++i; // Skip unused "parent dir" argument.
      while (i < argc) {
      const char* arg = argv[i++];
      if (strcmp(arg, "--zygote") == 0) {
      zygote = true;
      niceName = ZYGOTE_NICE_NAME;
      } else if (strcmp(arg, "--start-system-server") == 0) {
      startSystemServer = true;
      } else if (strcmp(arg, "--application") == 0) {
      application = true;
      } else if (strncmp(arg, "--nice-name=", 12) == 0) {
      niceName.setTo(arg + 12);
      } else if (strncmp(arg, "--", 2) != 0) {
      className.setTo(arg);
      break;
      } else {
      --i;
      break;
      }
      }

      Vector<String8> args;
      if (!className.isEmpty()) {
      // We're not in zygote mode, the only argument we need to pass
      // to RuntimeInit is the application argument.
      //
      // The Remainder of args get passed to startup class main(). Make
      // copies of them before we overwrite them with the process name.
      args.add(application ? String8("application") : String8("tool"));
      runtime.setClassNameAndArgs(className, argc - i, argv + i);

      if (!LOG_NDEBUG) {
      String8 restOfArgs;
      char* const* argv_new = argv + i;
      int argc_new = argc - i;
      for (int k = 0; k < argc_new; ++k) {
      restOfArgs.append("\"");
      restOfArgs.append(argv_new[k]);
      restOfArgs.append("\" ");
      }
      ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
      }
      } else {
      // We're in zygote mode.
      maybeCreateDalvikCache();

      if (startSystemServer) {
      args.add(String8("start-system-server"));
      }

      char prop[PROP_VALUE_MAX];
      if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
      LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
      ABI_LIST_PROPERTY);
      return 11;
      }

      String8 abiFlag("--abi-list=");
      abiFlag.append(prop);
      args.add(abiFlag);

      // In zygote mode, pass all remaining arguments to the zygote
      // main() method.
      for (; i < argc; ++i) {
      args.add(String8(argv[i]));
      }
      }

      if (!niceName.isEmpty()) {
      runtime.setArgv0(niceName.string(), true /* setProcName */);
      }

      if (zygote) {
      runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
      } else if (className) {
      runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
      } else {
      fprintf(stderr, "Error: no class name or --zygote supplied.\n");
      app_usage();
      LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
      }
      }
      app_main.cpp

      server

      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
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      package com.algorithm.sample.socket;

      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import java.io.PrintStream;
      import java.net.ServerSocket;
      import java.net.Socket;

      public class SocketServer {
      public static void main(String[] args) {
      try {
      ServerSocket serverSocket = new ServerSocket(8081);
      while (true) {
      //从请求队列中取出一个连接
      Socket client = serverSocket.accept();
      // 处理这次连接
      new HandlerThread(client);

      }
      }catch (Exception e){
      e.printStackTrace();
      System.out.println("服务器异常: " + e.getMessage());
      }
      }
      private static class HandlerThread implements Runnable {
      private Socket socket;
      public HandlerThread(Socket client) {
      socket = client;
      new Thread(this).start();
      }

      public void run() {
      try {
      // 读取客户端数据
      BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      String clientInputStr = input.readLine();//这里要注意和客户端输出流的写方法对应,否则会抛 EOFException
      // 处理客户端数据
      System.out.println("客户端发过来的内容:" + clientInputStr);

      // 向客户端回复信息
      PrintStream out = new PrintStream(socket.getOutputStream());
      out.println("我收到消息了");
      out.close();
      input.close();
      } catch (Exception e) {
      System.out.println("服务器 run 异常: " + e.getMessage());
      } finally {
      if (socket != null) {
      try {
      socket.close();
      } catch (Exception e) {
      socket = null;
      System.out.println("服务端 finally 异常:" + e.getMessage());
      }
      }
      }
      }
      }
      }

      dx

      1
      2
      3
      # /server/build/classes/java/main 为idea编译器编译后的out目录,我们直接使用
      # 制作的dex为server端
      ./dx --dex --output=/Users/juneleo/Desktop/socket2.dex /server/build/classes/java/main

app_process

1
2
3
4
# push
adb push /Users/juneleo/Desktop/socket.dex /data/local/tmp/
#启动 app_process
adb shell app_process -Djava.class.path=/data/local/tmp/socket.dex /data/local/tmp --nice-name=songpengfei com.algorithm.sample.socket.SocketServer

client

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
47
48
49
50
51
52
53
54
package com.algorithm.sample.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class SocketClient {
public static final int port = 8081;
public static final String host = "30.28.48.73";
public static void main(String[] args) {
System.out.println("Client Start...");
while (true) {
Socket socket = null;
try {
//创建一个流套接字并将其连接到指定主机上的指定端口号
socket = new Socket(host,port);

//读取服务器端数据
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//向服务器端发送数据
PrintStream out = new PrintStream(socket.getOutputStream());
System.out.print("请输入: \t");
String str = new BufferedReader(new InputStreamReader(System.in)).readLine();
out.println(str);

String ret = input.readLine();
System.out.println("服务器端返回过来的是: " + ret);
// 如接收到 "OK" 则断开连接
if ("OK".equals(ret)) {
System.out.println("客户端将关闭连接");
Thread.sleep(500);
break;
}

out.close();
input.close();
} catch (Exception e) {
System.out.println("客户端异常:" + e.getMessage());
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
socket = null;
System.out.println("客户端 finally 异常:" + e.getMessage());
}
}
}
}
}
}