🌒MoonLab

> 在MoonLab中搜索

  1. 1. 前言
    1. 1.1. Shizuku 是什么?
  2. 2. 正文
    1. 2.1. ShizukuBinderWrapper
    2. 2.2. IShizukuService
    3. 2.3. ShizukuService 的启动
  3. 3. 末语

Android Shizuku源码分析

Category: Programming

🏷️  Android   中文

前言

上一篇文章我使用了 Shizuku 去调用系统API:文章链接

这次就来看看 Shizuku 的源码是怎么写的。

最开始我用 Notepad++ 看,最后还是用 as 看源码好点吧。

官方文档

酷安下载 ShizukuManager

Watch it on GitHub

Shizuku 是什么?

Shizuku app 会引导用户使用 root 或是 adb 方式运行一个进程(Shizuku 服务进程)。

  1. 应用进程启动时 Shizuku 服务进程发送 binder 至应用进程
  2. 应用通过该 binder 与 Shizuku 服务进程交互,Shizuku 服务进程通过 binder 与 system server 交互

正文

ShizukuBinderWrapper

首先我们看,在开发时调用 Shizuku 的代码:

private static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));

它使我们能随意调用 Android 系统中 IPackageManager 内的方法,也就是系统隐藏的API(有 @hide 标签的方法)

我们可以看到 ShizukuBinderWrapper 的构造方法内传入了一个 SystemServiceHelper#getSystemService 方法的返回值。

private static Map<String, IBinder> systemServiceCache = new HashMap<>(); 
public static IBinder getSystemService(@NonNull String name) {
        IBinder binder = systemServiceCache.get(name);
        if (binder == null) {
            binder = ServiceManager.getService(name);
            systemServiceCache.put(name, binder);
        }
        return binder;
}

getSystemService 方法先查询了一下缓存,如果没有缓存就调用 ServiceManager 的 getService 方法。这个本地的 ServiceManager 是在 android.os 包下:

package android.os;

public class ServiceManager {

    public static IBinder getService(String name) {
        throw new UnsupportedOperationException();
    }
}

getService 方法会根据 name 参数返回一个 IBinder 接口,我们可以查一下 Android 源码中的 ServiceManager 类:

public final class ServiceManager {
    /**
     * Returns a reference to a service with the given name.
     *
     * @param name the name of the service to get
     * @return a reference to the service, or <code>null</code> if the service doesn't exist
     */
    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return Binder.allowBlocking(rawGetService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
}

其中 getService 不是 hide 方法可以直接调用。

我们看看 ShizukuBinderWrapper 的构造参数:

 private IBinder original;

// original 是 ServiceManager.getService 返回的 IBinder
 public ShizukuBinderWrapper(@NonNull IBinder original) {
     // 使用 requireNonNull 方法判断是否为 null,如果为 null 抛出空指针异常。
     this.original = Objects.requireNonNull(original);
 }

这个构造参数对 original 进行了赋值,这是一个 IBinder。

我们将这个 ShizukuBinderWrapper 传入Binder 的 asInterface 就能获得适用于客户端的 Binder 随意调用 IPackageiManager 内的方法,其中我在本地写的 IPackageManager 只是个空壳接口,只继承了 IInterface 声明了需要的方法:

package android.content.pm;
// 与 Android 系统内的 IPackageManager 在同一个包下

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;

public interface IPackageManager extends IInterface {

    // 我只需要这个方法,所以只声明这个方法来调用
    ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) throws RemoteException;

    abstract class Stub extends Binder implements IPackageManager {

        public static IPackageManager asInterface(IBinder obj) {
            throw new UnsupportedOperationException();
        }
    }
}

我们查看 ShizukuBinderWrapper 的源码, ShizukuBinderWrapper 本身就实现了 IBinder 接口,所以可以直接作为上述 asInterface 方法的参数。

这是 ShizukuBinderWrapper 中的 transact 方法的重写:

/* ShizukuBinderWrapper#transact */
  @Override
  public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
      Parcel newData = Parcel.obtain();
      try {
          // 使用 writeInterfaceToken 写入 ShizukuApiConstants.BINDER_DESCRIPTOR,用于后面服务端的判断
          newData.writeInterfaceToken(ShizukuApiConstants.BINDER_DESCRIPTOR);
          // 写入了 original 这个 Binder
          newData.writeStrongBinder(original);
          newData.writeInt(code);
          newData.appendFrom(data, 0, data.dataSize());
          ShizukuService.transactRemote(newData, reply, flags);
      } finally {
          newData.recycle();
      }
      return true;
  }

我们都知道,在 aidl 中我们调用 Binder 的方法时实际上都调用了这个 transact 方法。

例如:

private static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));

ParceledListSlice<PackageInfo> listSlice = PACKAGE_MANAGER.getInstalledPackages(flags, userId);

这里我调用 getInstalledPackages 方法时,方法的内部实际上就调用了上面 ShizukuBinderWrapper 这个 Binder 的 transact 方法。在调用 getInstalledPackages 这个系统方法时,它内部就把我们调用系统方法所传入的参数写入了 data 中再传入这个 ShizukuBinderWrapper 的 transact 方法。

ShizukuBinderWrapper 的 transact 方法又把 data 和 reply 传入了 ShizukuService 的 transactRemote 下,这个 ShizukuService 是一个普通的类里面有一些静态变量和方法。

package moe.shizuku.api;
/* ShizukuService#transactRemote */
public static void transactRemote(@NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
// 调用 ShizukuService 的 requireService 方法
requireService().asBinder().transact(ShizukuApiConstants.BINDER_TRANSACTION_transact, data, reply, flags);
}

我们可以看到,这个方法由调用了 requireService 方法取得了 Binder 再调用 Binder 的 transact 方法与服务端通信 ,再看看 requireService 方法:

private static IShizukuService requireService() {
        if (getService() == null) {
            throw new IllegalStateException("Binder haven't received, check Shizuku and your code.");
        }
        return getService();
    }

没什么好解释,继续看 getService 方法。

/* ShizukuService */ 
    private static IShizukuService sService;

    public static void setBinder(IBinder binder) {
        sService = IShizukuService.Stub.asInterface(binder);
    }

    private static IShizukuService getService() {
        return sService;
    }

这个 getService 静态方法会返回一个 IShizukuService 类型的 mService,而这个 mService 是由 setBinder 设置的,那么是谁调用了这个 ShizukuService.setBinder 方法来设置 mService ?我们先不管它。

IShizukuService

我们再注意一下这个 IShizukuService:

/* IShizukuService.aidl */
package moe.shizuku.server;

import moe.shizuku.server.IRemoteProcess;

interface IShizukuService {

    int getVersion() = 2;

    int getUid() = 3;

    int checkPermission(String permission) = 4;

    String getToken() = 5;

    boolean setPidToken(in String token) = 6;

    IRemoteProcess newProcess(in String[] cmd, in String[] env, in String dir) = 7;

    String getSELinuxContext() = 8;
}

这个 AIDL 的作用是让我们开发的应用与 Shhizuku 的系统进程进行 Binder 通信。

我们之前的 transactRemote 方法已经调用了它的 Binder 的 transact 方法开始联系服务端挂起客户端了。

我们再看与 IShizukuService 相关的类:

package moe.shizuku.service
public class ShizukuService extends IShizukuService.Stub {
    ...
}

它不同于我们刚才看到的 moe.shizuku.api 下的 ShizukuService ,这是 moe.shizuku.service 下的 ShizukuService。是一个真真正正的服务端,和 Android 系统中的系统服务(例如AMS, PMS)类似没有直接继承 Service 类,而是继承自一个 Binder(后面我们再说)。

接下来我们看它重写的 onTransact 方法:

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    if (code == ShizukuApiConstants.BINDER_TRANSACTION_transact) {
        data.enforceInterface(ShizukuApiConstants.BINDER_DESCRIPTOR);
        transactRemote(data, reply, flags);
        return true;
    }
    return super.onTransact(code, data, reply, flags);
}

先用 enforceInterface 方法检查一下 Interface 是否与客户端的相同,再调用了 transactRemote 方法:

private void transactRemote(Parcel data, Parcel reply, int flags) throws RemoteException {
       IBinder targetBinder = data.readStrongBinder();
       int targetCode = data.readInt();
       enforceCallingPermission("transactRemote", true);
       targetBinder.getInterfaceDescriptor(), targetCode);
       Parcel newData = Parcel.obtain();
       try {
           newData.appendFrom(data, data.dataPosition(), data.dataAvail());
       } catch (Throwable tr) {
           LOGGER.w(tr, "appendFrom");
           return;
       }
       try {
           long id = Binder.clearCallingIdentity();
           // here
           targetBinder.transact(targetCode, newData, reply, flags);
           Binder.restoreCallingIdentity(id);
       } finally {
           newData.recycle();
       }
   }

我们可以看到 targetBinder 其实就是我们之前用 SystemServiceHelper 的 getService 方法得到的 Binder,在调用它的 transact 方法,实现 Shizuku 服务与你想要通信的系统服务进行 Binder 通信,毕竟 Shizuku 服务已经通过 adb 或 root 成为了 dalao。

ShizukuService 的启动

上面我们看到了我们用到了 ShizukuService 去完成应用与系统服务的通信,而这个静态变量 mService 是通过 ShizukuService#setBinder 方法设置的:

package moe.shizuku.api;

public class ShizukuService {
    private static IShizukuService sService;

    public static void setBinder(IBinder binder) {
        sService = IShizukuService.Stub.asInterface(binder);
    }
}

首先,Starter 类中的 main 方法会启动 ShizukuService 服务:

public static void main(String[] args) throws IOException, RemoteException, InterruptedException {
       fixFilesOwner();

       waitServiceManager();
       waitSystemService("package");
       waitSystemService("activity");
       waitSystemService(Context.USER_SERVICE);
       waitSystemService(Context.APP_OPS_SERVICE);

       checkManagerApp();

       if (Build.VERSION.SDK_INT >= 28) {
           disableHiddenApiBlacklist();
       }

       LOGGER.i("server v3");

       Looper.prepare();

       // 这是 moe.shizuku.service 包下的继承自 Binder 的 ShizukuService
       ShizukuService server = new ShizukuService(getToken(args));
       server.sendBinderToManager();
       server.sendBinderToClients();
       Looper.loop();

       LOGGER.i("server exit");
       System.exit(0);
   }

可以看到这里直接 new 了一个 ShizukuService 实例,这和一些系统服务启动方法类似。

其中调用了 ShizukuService 的 sendBinderToClients 方法,这中间有一大堆 dalao 操作,我们不作详细关注,泥萌可自行阅读源码。

最后会调用 ShuzikuService 的 sendBinderToUserApp 方法,略过了一些其他的代码:

static void sendBinderToUserApp(Binder binder, String packageName, int userId) {
    ...
     Bundle extra = new Bundle();
     extra.putParcelable(ShizukuApiConstants.EXTRA_BINDER, new BinderContainer(binder));
     Bundle reply = IContentProviderHelper.call(provider, null, name, "sendBinder", null, extra);
    ...
}

将 ShizukuService 这个 Binder 包装成一个 BinderContainer 类然后放入 Bundle 里。

这个 IContentProviderHelper 的 call 方法会跨进程调用 ShizukuBinderReceiveProvider 这个 ContentProvider 的 call 方法:

 @Nullable
 @Override
public final Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
        if (extras == null)
            return null;
        Bundle reply = new Bundle();
        extras.setClassLoader(BinderContainer.class.getClassLoader());
        switch (method) {
            case METHOD_SEND_BINDER: {
                if (ShizukuService.pingBinder()) {
                    Log.i("ShizukuClient", "ShizukuBinderReceiveProvider started when already a binder alive");
                    break;
                }
                BinderContainer container = extras.getParcelable(ShizukuApiConstants.EXTRA_BINDER);
                if (container != null && container.binder != null) {
                    Log.i("ShizukuClient", "binder received");
                    // 调用 ShizukuService 的 setBinder 静态方法将静态变量 mService 设置成之前在 app_process 进程启动的 ShizukuService 的 Binder
                    ShizukuService.setBinder(container.binder);
                    //noinspection ConstantConditions
                    Intent intent = new Intent(ShizukuMultiProcessHelper.ACTION_BINDER_RECEIVED)
                            .putExtra(ShizukuApiConstants.EXTRA_BINDER, container)
                            .setPackage(getContext().getPackageName());
                    getContext().sendBroadcast(intent);
                }
                ...
                break;
            }
            ...
        }
        return reply;
}

其中调用了 ShizukuService 的 setBinder 方法,将 IShuzukuService 传进去了。

末语

实际上这只分析了一部分,关于 ShizukuService 具体的如何启动,这个 main 方法是怎么调用的,和关于 start.sh 的一些问题,或许有生之年我能写出第二篇文章…

Shizuku 内还有好多 dalao操作,我都没有去看,只把重要的一部分写了下来。

果然只有 dalao才能这样操作,我还是继续躺着吧。

Orz


2020-02-04:

时隔两天,我又写出了第二篇文章啦:https://lcblog.cn/post/android-shizuku-theory2

尝试具体分析 Starter 类是如何启动的。

2018-2023 MoonLab