Shizuku 源码解读(自动解锁手机抢购飞天茅台)

自动解锁手机抢购京东飞天茅台

每天定时抢购飞天茅台

原视频链接

  • Shizuku Apk

      1. 执行 adb shell sh /sdcard/Android/data/li.songe.gkd.debug/start.sh
      • copy 可执行文件

        • copy starter from /storage/emulated/0/Android/data/li.songe.gkd.debug/starter to /data/local/tmp/shizuku_starter

      • 增加执行权限starter.ELF

      • 执行文件starter.ELF

      • 执行starter.cpp

        • 创建守护进程 if (daemon(false, false) == 0)

        • 运行java文件rikka.shizuku.server.ShizukuService 进程名称 shizuku_server

        • static void run_server(const char *dex_path, const char *main_class, const char *process_name) {
              if (setenv("CLASSPATH", dex_path, true)) {
                  LOGE("can't set CLASSPATH\n");
                  exit(EXIT_FATAL_SET_CLASSPATH);
              }
          
          #define ARG(v) char **v = nullptr; \
              char buf_##v[PATH_MAX]; \
              size_t v_size = 0; \
              uintptr_t v_current = 0;
          #define ARG_PUSH(v, arg) v_size += sizeof(char *); \
          if (v == nullptr) { \
              v = (char **) malloc(v_size); \
          } else { \
              v = (char **) realloc(v, v_size);\
          } \
          v_current = (uintptr_t) v + v_size - sizeof(char *); \
          *((char **) v_current) = arg ? strdup(arg) : nullptr;
          
          #define ARG_END(v) ARG_PUSH(v, nullptr)
          
          #define ARG_PUSH_FMT(v, fmt, ...) snprintf(buf_##v, PATH_MAX, fmt, __VA_ARGS__); \
              ARG_PUSH(v, buf_##v)
          
          #ifdef JAVA_DEBUGGABLE
          #define ARG_PUSH_DEBUG_ONLY(v, arg) ARG_PUSH(v, arg)
          #define ARG_PUSH_DEBUG_VM_PARAMS(v) \
              if (android::GetApiLevel() >= 30) { \
                  ARG_PUSH(v, "-Xcompiler-option"); \
                  ARG_PUSH(v, "--debuggable"); \
                  ARG_PUSH(v, "-XjdwpProvider:adbconnection"); \
                  ARG_PUSH(v, "-XjdwpOptions:suspend=n,server=y"); \
              } else if (android::GetApiLevel() >= 28) { \
                  ARG_PUSH(v, "-Xcompiler-option"); \
                  ARG_PUSH(v, "--debuggable"); \
                  ARG_PUSH(v, "-XjdwpProvider:internal"); \
                  ARG_PUSH(v, "-XjdwpOptions:transport=dt_android_adb,suspend=n,server=y"); \
              } else { \
                  ARG_PUSH(v, "-Xcompiler-option"); \
                  ARG_PUSH(v, "--debuggable"); \
                  ARG_PUSH(v, "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y"); \
              }
          #else
          #define ARG_PUSH_DEBUG_VM_PARAMS(v)
          #define ARG_PUSH_DEBUG_ONLY(v, arg)
          #endif
          
              char lib_path[PATH_MAX]{0};
              snprintf(lib_path, PATH_MAX, "%s!/lib/%s", dex_path, ABI);
          
              ARG(argv)
              ARG_PUSH(argv, "/system/bin/app_process")
              ARG_PUSH_FMT(argv, "-Djava.class.path=%s", dex_path)
              ARG_PUSH_FMT(argv, "-Dshizuku.library.path=%s", lib_path)
              ARG_PUSH_DEBUG_VM_PARAMS(argv)
              ARG_PUSH(argv, "/system/bin")
              ARG_PUSH_FMT(argv, "--nice-name=%s", process_name)
              ARG_PUSH(argv, main_class)
              ARG_PUSH_DEBUG_ONLY(argv, "--debug")
              ARG_END(argv)
          
              LOGD("exec app_process");
          
              if (execvp((const char *) argv[0], argv)) {
                  exit(EXIT_FATAL_APP_PROCESS);
              }
          }
          
      1. 通过上面的执行:进程shizuku_server 已经创建运行
      • 进入loop循环模式

        •  public static void main(String[] args) {
                  DdmHandleAppName.setAppName("shizuku_server", 0);
                  LOGGER.i("gzp_ShizukuService getProperty" + System.getProperty("shizuku.library.path"));
                  RishConfig.setLibraryPath(System.getProperty("shizuku.library.path"));
                  Looper.prepareMainLooper();
                  new ShizukuService();
                  Looper.loop();
              }
          
      1. 将shizukuservice 发送给客户端(应用apk)sendBinderToClient
      • public ShizukuService() {
                super();
        
                HandlerUtil.setMainHandler(mainHandler);
        
                LOGGER.i("starting server...");
        
                waitSystemService("package");
                waitSystemService(Context.ACTIVITY_SERVICE);
                waitSystemService(Context.USER_SERVICE);
                waitSystemService(Context.APP_OPS_SERVICE);
        
                ApplicationInfo ai = getManagerApplicationInfo();
                if (ai == null) {
                    System.exit(ServerConstants.MANAGER_APP_NOT_FOUND);
                }
        
                assert ai != null;
                managerAppId = ai.uid;
        
                configManager = getConfigManager();
                clientManager = getClientManager();
        
                ApkChangedObservers.start(ai.sourceDir, () -> {
                    if (getManagerApplicationInfo() == null) {
                        LOGGER.w("manager app is uninstalled in user 0, exiting...");
                        System.exit(ServerConstants.MANAGER_APP_NOT_FOUND);
                    }
                });
        
                BinderSender.register(this);
        
                mainHandler.post(() -> {
                    sendBinderToClient();
                    sendBinderToManager();
                });
            }
        
      • 调用 sendBinderToUserApp

        • static void sendBinderToUserApp(Binder binder, String packageName, int userId, boolean retry) {
                  try {
                      DeviceIdleControllerApis.addPowerSaveTempWhitelistApp(packageName, 30 * 1000, userId,
                              316/* PowerExemptionManager#REASON_SHELL */, "shell");
                      LOGGER.v("Add %d:%s to power save temp whitelist for 30s", userId, packageName);
                  } catch (Throwable tr) {
                      LOGGER.e(tr, "Failed to add %d:%s to power save temp whitelist", userId, packageName);
                  }
          
                  String name = packageName + ".shizuku";
                  IContentProvider provider = null;
          
                  /*
                   When we pass IBinder through binder (and really crossed process), the receive side (here is system_server process)
                   will always get a new instance of android.os.BinderProxy.
          
                   In the implementation of getContentProviderExternal and removeContentProviderExternal, received
                   IBinder is used as the key of a HashMap. But hashCode() is not implemented by BinderProxy, so
                   removeContentProviderExternal will never work.
          
                   Luckily, we can pass null. When token is token, count will be used.
                   */
                  IBinder token = null;
          
                  try {
                      provider = ActivityManagerApis.getContentProviderExternal(name, userId, token, name);
                      if (provider == null) {
                          LOGGER.e("provider is null %s %d", name, userId);
                          return;
                      }
                      if (!provider.asBinder().pingBinder()) {
                          LOGGER.e("provider is dead %s %d", name, userId);
          
                          if (retry) {
                              // For unknown reason, sometimes this could happens
                              // Kill Shizuku app and try again could work
                              ActivityManagerApis.forceStopPackageNoThrow(packageName, userId);
                              LOGGER.e("kill %s in user %d and try again", packageName, userId);
                              Thread.sleep(1000);
                              sendBinderToUserApp(binder, packageName, userId, false);
                          }
                          return;
                      }
          
                      if (!retry) {
                          LOGGER.e("retry works");
                      }
          
                      Bundle extra = new Bundle();
                      extra.putParcelable("moe.shizuku.privileged.api.intent.extra.BINDER", new BinderContainer(binder));
          
                      Bundle reply = IContentProviderUtils.callCompat(provider, null, name, "sendBinder", null, extra);
                      if (reply != null) {
                          LOGGER.i("send binder to user app %s in user %d", packageName, userId);
                      } else {
                          LOGGER.w("failed to send binder to user app %s in user %d", packageName, userId);
                      }
                  } catch (Throwable tr) {
                      LOGGER.e(tr, "failed send binder to user app %s in user %d", packageName, userId);
                  } finally {
                      if (provider != null) {
                          try {
                              ActivityManagerApis.removeContentProviderExternal(name, token);
                          } catch (Throwable tr) {
                              LOGGER.w(tr, "removeContentProviderExternal");
                          }
                      }
                  }
              }
          
        • binder被包装成BinderContainer,塞到Bundle 中,binder就是ShizukuService

      1. 将shizukuservice 发送给Shizuku (应用apk)
      • 调用 sendBinderToManager

        •     static void sendBinderToManger(Binder binder, int userId) {
                  sendBinderToUserApp(binder, MANAGER_APPLICATION_ID, userId);
              }
              public static final String MANAGER_APPLICATION_ID = "moe.shizuku.privileged.api";
          
          
      1. 至此 应用客户端 和Shizuku 客户端都持有 shizukuService的binder
  • 应用 Apk

      1. androidMainfest 清单文件申明shuzuku的ShizukuProvider
      • 接受Shizuku的server (binder)

      •   <provider
                    android:name="rikka.shizuku.ShizukuProvider"
                    android:authorities="${applicationId}.shizuku"
                    android:enabled="true"
                    android:exported="true"
                    android:multiprocess="false"
                    android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
        
        
      1. 当shizuku的 shizuku_server 进程 创建以后,后发送shizukuserver 的 binder到ShizukuProvider;
        1. 解析Bundle,得到BinderContainer(得到shizhukuservice)
        •  private void handleSendBinder(@NonNull Bundle extras) {
                  if (Shizuku.pingBinder()) {
                      Log.d(TAG, "sendBinder is called when already a living binder");
                      return;
                  }
          
                  BinderContainer container = extras.getParcelable(EXTRA_BINDER);
                  if (container != null && container.binder != null) {
                      Log.d(TAG, "binder received");
          
                      Shizuku.onBinderReceived(container.binder, getContext().getPackageName());
          
                      if (enableMultiProcess) {
                          Log.d(TAG, "broadcast binder");
          
                          Intent intent = new Intent(ACTION_BINDER_RECEIVED)
                                  .putExtra(EXTRA_BINDER, container)
                                  .setPackage(getContext().getPackageName());
                          getContext().sendBroadcast(intent);
                      }
                  }
              }
          
        1. shizuku api 保存 Shizukuservice 的binder 应用进程中的Shizuku
        •  @RestrictTo(LIBRARY_GROUP_PREFIX)
              public static void onBinderReceived(@Nullable IBinder newBinder, String packageName) {
                  if (binder == newBinder) return;
          
                  if (newBinder == null) {
                      binder = null;
                      service = null;
                      serverUid = -1;
                      serverApiVersion = -1;
                      serverContext = null;
          
                      scheduleBinderDeadListeners();
                  } else {
                      if (binder != null) {
                          binder.unlinkToDeath(DEATH_RECIPIENT, 0);
                      }
                      binder = newBinder;
                      service = IShizukuService.Stub.asInterface(newBinder);
          
                      try {
                          binder.linkToDeath(DEATH_RECIPIENT, 0);
                      } catch (Throwable e) {
                          Log.i("ShizukuApplication", "attachApplication");
                      }
          
                      try {
                          if (!attachApplicationV13(binder, packageName) && !attachApplicationV11(binder, packageName)) {
                              preV11 = true;
                          }
                          Log.i("ShizukuApplication", "attachApplication");
                      } catch (Throwable e) {
                          Log.w("ShizukuApplication", Log.getStackTraceString(e));
                      }
          
                      if (preV11) {
                          binderReady = true;
                          scheduleBinderReceivedListeners();
                      }
                  }
              }
          
        1. 多进程 发送广播通知
    • 通过上面步骤,应用客户端已经保留shizukuService的binder

  • 应用 Apk bindService :

      1. 应用 Apk 发起 binderService
      •     public static void bindUserService(@NonNull UserServiceArgs args, @NonNull ServiceConnection conn) {
                ShizukuServiceConnection connection = ShizukuServiceConnections.get(args);
                connection.addConnection(conn);
                try {
                    requireService().addUserService(connection, args.forAdd());
                } catch (RemoteException e) {
                    throw rethrowAsRuntimeException(e);
                }
            }
        
      1. binder 跨应用进程到进程shizuku_server中ShizukuService
      • ShizukuService 处理addUserservice
      1. 应用apk 收到连接回调,binder 就是应用apk 中的服务
      • private final ServiceConnection userServiceConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName componentName, IBinder binder) {
                    if (binder != null && binder.pingBinder()) {
                        IUserService service = IUserService.Stub.asInterface(binder);
                        try {
                            service.doSomething();
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    } 
                }
        
                @Override
                public void onServiceDisconnected(ComponentName componentName) {
                }
            };
        
  • ShizukuService 处理addUserservice

      1. 解析参数并保存,生成 UserServiceRecord
      •  public int addUserService(IShizukuServiceConnection conn, Bundle options, int callingApiVersion) {
              	...
                ComponentName componentName = Objects.requireNonNull(options.getParcelable(USER_SERVICE_ARG_COMPONENT), "component is null");
                String packageName = Objects.requireNonNull(componentName.getPackageName(), "package is null");
                PackageInfo packageInfo = ensureCallingPackageForUserService(packageName, appId, userId);
        
                String className = Objects.requireNonNull(componentName.getClassName(), "class is null");
                String sourceDir = Objects.requireNonNull(packageInfo.applicationInfo.sourceDir, "apk path is null");
        
                int versionCode = options.getInt(USER_SERVICE_ARG_VERSION_CODE, 1);
                String tag = options.getString(USER_SERVICE_ARG_TAG);
                String processNameSuffix = options.getString(USER_SERVICE_ARG_PROCESS_NAME);
                boolean debug = options.getBoolean(USER_SERVICE_ARG_DEBUGGABLE, false);
                boolean noCreate = options.getBoolean(USER_SERVICE_ARG_NO_CREATE, false);
                boolean daemon = options.getBoolean(USER_SERVICE_ARG_DAEMON, true);
                boolean use32Bits = options.getBoolean(USER_SERVICE_ARG_USE_32_BIT_APP_PROCESS, false);
                String key = packageName + ":" + (tag != null ? tag : className);
        
                synchronized (this) {
                    UserServiceRecord record = getUserServiceRecordLocked(key);
                    if (noCreate) {
                        if (record != null) {
                            record.callbacks.register(conn);
        
                            if (record.service != null && record.service.pingBinder()) {
                                record.broadcastBinderReceived();
        
                                if (callingApiVersion >= 13) {
                                    return record.versionCode;
                                } else {
                                    return 0;
                                }
                            }
                        }
        
                        if (callingApiVersion >= 13) {
                            return -1;
                        } else {
                            return 1;
                        }
                    } else {
                        UserServiceRecord newRecord = createUserServiceRecordIfNeededLocked(record, key, versionCode, daemon, packageInfo);
                        newRecord.callbacks.register(conn);
        
                        if (newRecord.service != null && newRecord.service.pingBinder()) {
                            newRecord.broadcastBinderReceived();
                        } else if (!newRecord.starting) {
                            newRecord.setStartingTimeout(DateUtils.SECOND_IN_MILLIS * 30);
        
                            Runnable runnable = () -> startUserService(newRecord, key, newRecord.token, packageName, className, processNameSuffix, uid, use32Bits, debug);
                            executor.execute(runnable);
                            return 0;
                        }
                        return 0;
                    }
                }
            }
        
        
      1. 开启新的shell进程 UserServiceManager# startUserService ^^shell 进程 进程名称:packageName:service^^
        1. 开启新的shell进程
        •  private void startUserService(
                      UserServiceRecord record, String key, String token, String packageName,
                      String classname, String processNameSuffix, int callingUid, boolean use32Bits, boolean debug) {
          
                  LOGGER.v("Starting process for service record %s (%s)...", key, token);
          
                  String cmd = getUserServiceStartCmd(record, key, token, packageName, classname, processNameSuffix, callingUid, use32Bits && AbiUtil.has32Bit(), debug);
                  LOGGER.v("gzp cmd2: %s", cmd);
          
                  int exitCode;
                  try {
                      java.lang.Process process = Runtime.getRuntime().exec("sh");
                      OutputStream os = process.getOutputStream();
                      os.write(cmd.getBytes());
                      os.flush();
                      os.close();
          
                      exitCode = process.waitFor();
                  } catch (Throwable e) {
                      throw new IllegalStateException(e.getMessage());
                  }
                  if (exitCode != 0) {
                      throw new IllegalStateException("sh exited with " + exitCode);
                  }
              }
          
        1. 执行cmd
        • CLASSPATH='/data/app/li.songe.gkd.debug-c8Yb_FO5PS8KaLmGcLVbYQ==/base.apk' /system/bin/app_process -Xcompiler-option --debuggable -XjdwpProvider:internal -XjdwpOptions:transport=dt_android_adb,suspend=n,server=y /system/bin --nice-name='li.songe.gkd.debug:service' moe.shizuku.starter.ServiceStarter --token='ff773c49-13f5-4c80-a0a4-3219e79c3e0c-1708244575836' --package='li.songe.gkd.debug' --class='gzp.mt.service.UserService' --uid=10380 --debug-name=li.songe.gkd.debug:service)&
          
        1. 执行ServiceStarter.main方法
        •  public static void main(String[] args) {
                  if (Looper.getMainLooper() == null) {
                      Looper.prepareMainLooper();
                  }
          
                  IBinder service;
                  String token;
          
                  UserService.setTag(TAG);
                  Pair<IBinder, String> result = UserService.create(args);
          
                  if (result == null) {
                      System.exit(1);
                      return;
                  }
          
                  service = result.first;
                  token = result.second;
          
                  if (!sendBinder(service, token)) {
                      System.exit(1);
                  }
          
                  Looper.loop();
                  System.exit(0);
          
                  Log.i(TAG, "service exited");
              }
          
        1. 反射构造客户端service
        • public static Pair<IBinder, String> create(String[] args) {
                  String name = null;
                  String token = null;
                  String pkg = null;
                  String cls = null;
                  int uid = -1;
          
                  for (String arg : args) {
                      if (arg.startsWith("--debug-name=")) {
                          name = arg.substring(13);
                      } else if (arg.startsWith("--token=")) {
                          token = arg.substring(8);
                      } else if (arg.startsWith("--package=")) {
                          pkg = arg.substring(10);
                      } else if (arg.startsWith("--class=")) {
                          cls = arg.substring(8);
                      } else if (arg.startsWith("--uid=")) {
                          uid = Integer.parseInt(arg.substring(6));
                      }
                  }
          
                  int userId = uid / 100000;
          
                  Log.i(TAG, String.format("starting service %s/%s...", pkg, cls));
          
                  IBinder service;
          
                  try {
                      Context systemContext = ActivityThread.systemMain().getSystemContext();
          
                      DdmHandleAppName.setAppName(name != null ? name : pkg + ":user_service", 0);
          
                      //noinspection InstantiationOfUtilityClass
                      UserHandle userHandle = Refine.unsafeCast(
                              Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
                                      ? UserHandleHidden.of(userId)
                                      : new UserHandleHidden(userId));
                      Context context = Refine.<ContextHidden>unsafeCast(systemContext).createPackageContextAsUser(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY, userHandle);
                      ClassLoader classLoader = context.getClassLoader();
                      Class<?> serviceClass = classLoader.loadClass(cls);
                      Constructor<?> constructorWithContext = null;
                      try {
                          constructorWithContext = serviceClass.getConstructor(Context.class);
                      } catch (NoSuchMethodException | SecurityException ignored) {
                      }
                      if (constructorWithContext != null) {
                          service = (IBinder) constructorWithContext.newInstance(context);
                      } else {
                          service = (IBinder) serviceClass.newInstance();
                      }
                  } catch (Throwable tr) {
                      Log.w(TAG, String.format("unable to start service %s/%s...", pkg, cls), tr);
                      return null;
                  }
          
                  return new Pair<>(service, token);
              }
          
        1. 发送客户端service 到Shizuku Apk的 ShizukuManagerProvider
        •     private static boolean sendBinder(IBinder binder, String token, boolean retry) {
                  String packageName = "moe.shizuku.privileged.api";
                  String name = packageName + ".shizuku";
                  int userId = 0;
                  IContentProvider provider = null;
          
                  try {
                      provider = ActivityManagerApis.getContentProviderExternal(name, userId, null, name);
                      if (provider == null) {
                          Log.e(TAG, String.format("provider is null %s %d", name, userId));
                          return false;
                      }
                      if (!provider.asBinder().pingBinder()) {
                          Log.e(TAG, String.format("provider is dead %s %d", name, userId));
          
                          if (retry) {
                              // For unknown reason, sometimes this could happens
                              // Kill Shizuku app and try again could work
                              ActivityManagerApis.forceStopPackageNoThrow(packageName, userId);
                              Log.e(TAG, String.format("kill %s in user %d and try again", packageName, userId));
                              Thread.sleep(1000);
                              return sendBinder(binder, token, false);
                          }
                          return false;
                      }
          
                      if (!retry) {
                          Log.e(TAG, "retry works");
                      }
          
                      Bundle extra = new Bundle();
                      extra.putParcelable(EXTRA_BINDER, new BinderContainer(binder));
                      extra.putString(ShizukuApiConstants.USER_SERVICE_ARG_TOKEN, token);
          
                      Bundle reply = IContentProviderCompat.call(provider, null, null, name, "sendUserService", null, extra);
          
                      if (reply != null) {
                          reply.setClassLoader(BinderContainer.class.getClassLoader());
          
                          Log.i(TAG, String.format("send binder to %s in user %d", packageName, userId));
                          BinderContainer container = reply.getParcelable(EXTRA_BINDER);
          
                          if (container != null && container.binder != null && container.binder.pingBinder()) {
                              shizukuBinder = container.binder;
                              shizukuBinder.linkToDeath(() -> {
                                  Log.i(TAG, "exiting...");
                                  System.exit(0);
                              }, 0);
                              return true;
                          } else {
                              Log.w(TAG, "server binder not received");
                          }
                      }
          
                      return false;
                  } catch (Throwable tr) {
                      Log.e(TAG, String.format("failed send binder to %s in user %d", packageName, userId), tr);
                      return false;
                  } finally {
                      if (provider != null) {
                          try {
                              ActivityManagerApis.removeContentProviderExternal(name, null);
                          } catch (Throwable tr) {
                              Log.w(TAG, "removeContentProviderExternal", tr);
                          }
                      }
                  }
              }
          
          
        1. Shizuku Apk的 ShizukuManagerProvider 将 应用客户端的binder 继续发送给shizuku_server进程中的ShizukuServer,并且CDL 等待返回,将返回结果返回;
        • Shizuku.attachUserService(binder, bundleOf( USER_SERVICE_ARG_TOKEN to token))

        •  override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
                  if (extras == null) return null
          
                  return if (method == METHOD_SEND_USER_SERVICE) {
                      try {
                          extras.classLoader = BinderContainer::class.java.classLoader
          
                          val token = extras.getString(USER_SERVICE_ARG_TOKEN) ?: return null
                          val binder = extras.getParcelable<BinderContainer>(EXTRA_BINDER)?.binder ?: return null
          
                          val countDownLatch = CountDownLatch(1)
                          var reply: Bundle? = Bundle()
          
                          val listener = object : Shizuku.OnBinderReceivedListener {
          
                              override fun onBinderReceived() {
                                  try {
                                      Shizuku.attachUserService(binder, bundleOf(
                                          USER_SERVICE_ARG_TOKEN to token
                                      ))
                                      reply!!.putParcelable(EXTRA_BINDER, BinderContainer(Shizuku.getBinder()))
                                  } catch (e: Throwable) {
                                      LOGGER.e(e, "attachUserService $token")
                                      reply = null
                                  }
          
                                  Shizuku.removeBinderReceivedListener(this)
          
                                  countDownLatch.countDown()
                              }
                          }
          
                          Shizuku.addBinderReceivedListenerSticky(listener, workerHandler)
          
                          return try {
                              countDownLatch.await(5, TimeUnit.SECONDS)
                              reply
                          } catch (e: TimeoutException) {
                              LOGGER.e(e, "Binder not received in 5s")
                              null
                          }
                      } catch (e: Throwable) {
                          LOGGER.e(e, "sendUserService")
                          null
                      }
                  } else {
                      super.call(method, arg, extras)
                  }
              }
          
        1. ShizukuServer 通知客户端建立链接
        • public void broadcastBinderReceived() {
                  LOGGER.v("Broadcast binder received for service record %s", token);
          
                  int count = callbacks.beginBroadcast();
                  for (int i = 0; i < count; i++) {
                      try {
                          callbacks.getBroadcastItem(i).connected(service);
                      } catch (Throwable e) {
                          LOGGER.w("Failed to call connected %s", token);
                      }
                  }
                  callbacks.finishBroadcast();
              }
          
        1. 客户端拿到 packageName:service 对应的binder
        •  override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                  if (service?.pingBinder() == true) {
                      log(TAG, "onServiceConnected success")
                      mUserService = IUserService.Stub.asInterface(service)
                  } else {
                      log(TAG, "onServiceConnected pingBinder is false")
                  }
              }
          }
          
  • 补充

    • 包装成 ShizukuServiceConnection 发送给shizukuService

      • class ShizukuServiceConnection extends IShizukuServiceConnection.Stub

      • 通过 newRecord.callbacks.register(conn);

      • RemoteCallbackList

        RemoteCallbackList 是一个类似于列表的数据结构,它用于存储回调接口对象。每个回调接口对象都有一个唯一的 Binder 标识符,可以用来在不同进程之间进行传递和跟踪。RemoteCallbackList 的主要功能是提供了一组安全的 API,使得客户端可以注册、注销和通知回调接口对象,同时还提供了一些线程安全的方法,保证了并发操作的正确性。

      • RemoteCallbackList 的使用

        在使用 RemoteCallbackList 时,我们通常需要实现一个 Binder 服务或者一个 AIDL 接口,并在其中创建一个 RemoteCallbackList 对象。这个对象会被用来存储客户端注册的回调接口对象。

        • register(T callback):注册一个回调接口对象。

        • unregister(T callback):注销一个回调接口对象。

        • beginBroadcast():开始通知客户端,返回客户端数量。

        • getBroadcastItem(int index):获取指定位置的回调接口对象。

        • finishBroadcast():通知客户端结束。

  • 问题:

      1. 新进程中的context 如何构建创造
      1. hidden api的实现原理
  • 21
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值