深入研究安卓系统服务

整个系统服务开始

SystemServer.java

由静态函数开始所有系统服务的启动

1
2
3
public static void main(String[] args) {
new SystemServer().run();
}

并且在注释中找到了 adb 获取一些信息的方法,在 SystemServer 里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Service used to dump {@link SystemServer} state that is not associated with any service.
*
* <p>To dump all services:
*
* <pre><code>adb shell dumpsys system_server_dumper</code></pre>
*
* <p>To get a list of all services:
*
* <pre><code>adb shell dumpsys system_server_dumper --list</code></pre>
*
* <p>To dump a specific service (use {@code --list} above to get service names):
*
* <pre><code>adb shell dumpsys system_server_dumper --name NAME</code></pre>
*/

run

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void run() {
// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
startApexServices(t);
// Only update the timeout after starting all the services so that we use
// the default timeout to start system server.
updateWatchdogTimeout(t);
CriticalEventLog.getInstance().logSystemServerStarted();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}
}

其中 DisplayManagerServicestartBootstrapServices 中,startService 会调用 onStart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
***
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
t.traceEnd();

// We need the default display before we can initialize the package manager.
t.traceBegin("WaitForDisplay");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
t.traceEnd();
***
// DisplayManagerService needs to setup android.display scheduling related policies
// since setSystemProcess() would have overridden policies due to setProcessGroup
mDisplayManagerService.setupSchedulerPolicies();
}

SystemServiceManager.startService 定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@android.ravenwood.annotation.RavenwoodKeep
public void startService(@NonNull final SystemService service) {
// Check if already started
String className = service.getClass().getName();
if (mServiceClassnames.contains(className)) {
Slog.i(TAG, "Not starting an already started service " + className);
return;
}
mServiceClassnames.add(className);

// Register it.
mServices.add(service);

// Start it.
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}

也就是说 onStart 先于 startBootPhase

并且在 startOtherServices 调用了 windowManagerAndInputReady

1
2
3
4
5
6
7
8
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
***
// TODO: Use service dependencies instead.
t.traceBegin("DisplayManagerWindowManagerAndInputReady");
mDisplayManagerService.windowManagerAndInputReady();
t.traceEnd();
***
}

SystemServiceManager

SystemServiceManager.startBootPhase 定义,这里比较疑惑,在这个函数内部,会调用每个 ServiceonBootPhase 方法

但是 startBootPhaseSystemServer 中是会被多次调用的,后来看了一下,在每个实现的 onBootPhase 中,只处理自己相关的 phase

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
/**
* Starts the specified boot phase for all system services that have been started up to
* this point.
*
* @param t trace logger
* @param phase The boot phase to start.
*/
@android.ravenwood.annotation.RavenwoodKeep
public void startBootPhase(@NonNull TimingsTraceAndSlog t, int phase) {
if (phase <= mCurrentPhase) {
throw new IllegalArgumentException("Next phase must be larger than previous");
}
mCurrentPhase = phase;

Slog.i(TAG, "Starting phase " + mCurrentPhase);
try {
t.traceBegin("OnBootPhase_" + phase);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
long time = SystemClock.elapsedRealtime();
t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
} catch (Exception ex) {
throw new RuntimeException("Failed to boot service "
+ service.getClass().getName()
+ ": onBootPhase threw an exception during phase "
+ mCurrentPhase, ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
t.traceEnd();
}
} finally {
t.traceEnd();
}

if (phase == SystemService.PHASE_BOOT_COMPLETED) {
final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime;
t.logDuration("TotalBootTime", totalBootTime);
shutdownInitThreadPool();
}
}

并且发现一个函数,是可以启动其他 jar 内的服务的,当前所有代码是在 service.jar 中,可以将其他 jar 的类创建出来,放到当前 SystemServiceManager 中启动,并且能够注册服务,让普通 App 可以通过 context.getSystemService 获取到对应的服务

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
/**
* Starts a service by class name and standalone jar path where the service lives.
*
* In general, this should only be used for services in {@code STANDALONE_SYSTEMSERVER_JARS},
* which in turn derives from {@code PRODUCT_STANDALONE_SYSTEM_SERVER_JARS} and
* {@code PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS}.
*
* @return The service instance.
*/
public SystemService startServiceFromJar(String className, String path) {
PathClassLoader pathClassLoader =
SystemServerClassLoaderFactory.getOrCreateClassLoader(
path, this.getClass().getClassLoader(), isJarInTestApex(path));
final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
return startService(serviceClass);
}

public final class SystemServerClassLoaderFactory {
/**
* Creates and caches a ClassLoader for the jar at the given path.
*
* This method should only be called by ZygoteInit to prefetch jars. For other users, use
* {@link getOrCreateClassLoader} instead.
*
* The parent class loader should always be the system server class loader. Changing it has
* implications that require discussion with the mainline team.
*
* @hide for internal use only
*/
/* package */ static PathClassLoader createClassLoader(String path, ClassLoader parent) {
if (sLoadedPaths.containsKey(path)) {
throw new IllegalStateException("A ClassLoader for " + path + " already exists");
}
PathClassLoader pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader(
path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent,
Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null);
sLoadedPaths.put(path, pathClassLoader);
return pathClassLoader;
}

/**
* Returns a cached ClassLoader to be used at runtime for the jar at the given path. Or, creates
* one if it is not prefetched and is allowed to be created at runtime.
*
* The parent class loader should always be the system server class loader. Changing it has
* implications that require discussion with the mainline team.
*
* @hide for internal use only
*/
public static PathClassLoader getOrCreateClassLoader(
String path, ClassLoader parent, boolean isTestOnly) {
PathClassLoader pathClassLoader = sLoadedPaths.get(path);
if (pathClassLoader != null) {
return pathClassLoader;
}
if (!allowClassLoaderCreation(path, isTestOnly)) {
throw new RuntimeException("Creating a ClassLoader from " + path + " is not allowed. "
+ "Please make sure that the jar is listed in "
+ "`PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS` in the Makefile and added as a "
+ "`standalone_contents` of a `systemserverclasspath_fragment` in "
+ "`Android.bp`.");
}
return createClassLoader(path, parent);
}
}

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS =
"com.android.server.NetworkStatsServiceInitializer";
private static final String CONNECTIVITY_SERVICE_APEX_PATH =
"/apex/com.android.tethering/javalib/service-connectivity.jar";

/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
***
t.traceBegin("StartNetworkStatsService");
// This has to be called before NetworkPolicyManager because NetworkPolicyManager
// needs to take NetworkStatsService to initialize.
mSystemServiceManager.startServiceFromJar(NETWORK_STATS_SERVICE_INITIALIZER_CLASS,
CONNECTIVITY_SERVICE_APEX_PATH);
t.traceEnd();
***
}

这里感觉后面可以尝试一下,系统这边是将其他的 jar 以某种方式加载到了当前 service.jar,与我之前加载的方式有些区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    
scrcpy 中的方式
```java
Class<?> getDisplayManagerServiceFromFramework() {
String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
ClassLoader loader = ClassLoaderFactory.createClassLoader(
systemServerClasspath,
null,
null,
ClassLoader.getSystemClassLoader(),
0,
true,
null
);
try {
Class<?> clazz = serverClassLoader.loadClass("com.android.server.display.DisplayManagerService");
RH.iHM(Runtime.getRuntime(), "loadLibrary0", clazz, "android_servers");
return clazz;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}

后来又看了一下,这个是加载单个 jar,而我之前是加载整个 classpath 的 jar

再来看一下每一个服务做了什么

1
2
3
4
5
6
7
8
9
10
@VisibleForTesting
DisplayManagerService(Context context, Injector injector) {
}
@Override
public void onStart() {
// ***
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/, DUMP_FLAG_PRIORITY_CRITICAL);
publishLocalService(DisplayManagerInternal.class, new LocalService());
}

publishBinderService 应该就是将这个 ServiceBinder 的形式注入到系统服务,通过 AIDL 与普通 App 通信

通过 context.getSystemService(DisplayManager.class) 获取到的类型是 android.hardware.display.IDisplayManager$Stub$Proxy,这一类的类的父类是 IBinder

中文听力开始

IDisplayManager 就是一个 AIDL 接口

我们能用的也是 IDisplayManager 定义以及 DisplayManagerService.BinderService 中实现的方法

对普通 App 的调用链大概是这样的

App -> DisplayManager -> DisplayManagerGlobal -> IBinder(IDisplayManager\$Stub\$Proxy)

然后这个 IBinderDisplayManagerService.BinderService 去通信,DisplayManagerService.BinderService 去调用 DisplayManagerService 内部的方法,将结果通过 IBinder 返回给 App,实现跨进程的方法的调用

IBinder 通信核心代码应该是

1
2
public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
throws RemoteException;

Shizuku 的核心也借助 AIDL 来实现跨进程通信,不同的是 Shizuku 是在 app_process 运行的 dex server 中,去找集成了 Shizuku Provider 的 App,然后发送过去

Shizuku 的部分关键代码

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

所以我们要接入 Shizuku,需要使用它提供的 Provider,定义到 AndroidManifest.xml

我们自己使用 AIDL 的过程中,是不需要关心 code 之类的(应该),只需要定义好 AIDL 接口,生成的 java 大概是这样

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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
public interface IInputService extends android.os.IInterface
{
/** Default implementation for IInputService. */
public static class Default implements com.nightmare.neo.IInputService
{
@Override public void destroy() throws android.os.RemoteException
{
}
// Destroy method defined by Shizuku server
@Override public void exit() throws android.os.RemoteException
{
}
// Exit method defined by user
@Override public void injectEvent(int action, long pointerId, int x, int y, int width, int height, float pressure, int actionButton, int buttons, int source, int displayId) throws android.os.RemoteException
{
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.nightmare.neo.IInputService
{
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.nightmare.neo.IInputService interface,
* generating a proxy if needed.
*/
public static com.nightmare.neo.IInputService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.nightmare.neo.IInputService))) {
return ((com.nightmare.neo.IInputService)iin);
}
return new com.nightmare.neo.IInputService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
data.enforceInterface(descriptor);
}
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
}
switch (code)
{
case TRANSACTION_destroy:
{
this.destroy();
reply.writeNoException();
break;
}
case TRANSACTION_exit:
{
this.exit();
reply.writeNoException();
break;
}
case TRANSACTION_injectEvent:
{
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
int _arg2;
_arg2 = data.readInt();
int _arg3;
_arg3 = data.readInt();
int _arg4;
_arg4 = data.readInt();
int _arg5;
_arg5 = data.readInt();
float _arg6;
_arg6 = data.readFloat();
int _arg7;
_arg7 = data.readInt();
int _arg8;
_arg8 = data.readInt();
int _arg9;
_arg9 = data.readInt();
int _arg10;
_arg10 = data.readInt();
this.injectEvent(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10);
reply.writeNoException();
break;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
return true;
}
private static class Proxy implements com.nightmare.neo.IInputService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void destroy() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_destroy, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
// Destroy method defined by Shizuku server
@Override public void exit() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_exit, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
// Exit method defined by user
@Override public void injectEvent(int action, long pointerId, int x, int y, int width, int height, float pressure, int actionButton, int buttons, int source, int displayId) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(action);
_data.writeLong(pointerId);
_data.writeInt(x);
_data.writeInt(y);
_data.writeInt(width);
_data.writeInt(height);
_data.writeFloat(pressure);
_data.writeInt(actionButton);
_data.writeInt(buttons);
_data.writeInt(source);
_data.writeInt(displayId);
boolean _status = mRemote.transact(Stub.TRANSACTION_injectEvent, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_destroy = (android.os.IBinder.FIRST_CALL_TRANSACTION + 16777114);
static final int TRANSACTION_exit = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_injectEvent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
public static final java.lang.String DESCRIPTOR = "com.nightmare.neo.IInputService";
public void destroy() throws android.os.RemoteException;
// Destroy method defined by Shizuku server
public void exit() throws android.os.RemoteException;
// Exit method defined by user
public void injectEvent(int action, long pointerId, int x, int y, int width, int height, float pressure, int actionButton, int buttons, int source, int displayId) throws android.os.RemoteException;
}

可以发现编译器帮我们处理好了数据的打包和解包,我们只需要调用对应的方法即可,并且能通过 Binder 传输的数据类型是需要支持 Parcelable

整个系统服务的探索先到这,现在已经进入到 DisplayManagerServiceonStartonBootPhase

作者

梦魇兽

发布于

2025-11-04

更新于

2025-12-18

许可协议

评论