Java Binder 之 Binder

Binder是远端对象的基类,是IBinder定义的轻量级远程过程调用(RPC)机制的核心部分。该类是IBinder的实现,它提供了该类对象的本地标准实现。

大多数开发人员都不会直接实现此类,而是使用AIDL工具来描述需要的接口,并使其生成合适的Binder子类。可以直接从Binder派生实现自定义的RPC协议,也可以直接实例化原始Binder对象以用作可以在各个进程之间共享的token。

该类只是一个基本的IPC原语;它对应用程序的生命周期没有影响,并且仅在创建它的进程继续运行时才有效。

必须在顶级应用程序组件android.app.Serviceandroid.app.Activityandroid.content.ContentProvider的上下文中进行操作。让系统知道进程应保持运行状态。必须牢记进程可能会挂掉的情况,因此要重新创建一个新的binder,并在进程再次开始时重新连接它。例如,如果在android.app.Activity中使用它,则任何时候该activity未开始,它的activity进程都可能会被杀死;如果稍后重新创建了activity,则需要创建一个新的binder,然后将其重新放回正确的位置;进程可能是出于其他原因(如接收广播)而启动的,而这又不涉及重新创建activity,因此要运行其代码来创建新的binder。

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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
// frameworks/base/core/java/android/os/Binder.java
public class Binder implements IBinder {
// 将此flag设置为true可以检测扩展此Binder类,它不能是静态的匿名类、本地类或成员类,因为这些类可能会导致泄漏。
private static final boolean FIND_POTENTIAL_LEAKS = false;
public static final boolean CHECK_PARCEL_SIZE = false;
static final String TAG = "Binder";
public static boolean LOG_RUNTIME_EXCEPTION = false;
// 表明未设置调用工作源。该常量需要和IPCThreadState::kUnsetWorkSource保持同步。
public static final int UNSET_WORKSOURCE = -1;
// 控制dump()调用是否被允许。
private static volatile String sDumpDisabled = null;
// 此进程的全局事务跟踪器实例。
private static volatile TransactionTracker sTransactionTracker = null;
// 此进程的全局观察器。
private static BinderInternal.Observer sObserver = null;
// 与native内存关联的binder指标。
private static final int NATIVE_ALLOCATION_SIZE = 500;
private static native long getNativeFinalizer();
// 使用Holder可以在启动映像中静态初始化BinderProxy,并避免一些初始化顺序问题。
private static class NoImagePreloadHolder {
public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
Binder.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
}
// 标识是否跟踪事务调用过程。
private static volatile boolean sTracingEnabled = false;
// 使能Binder IPC跟踪。
public static void enableTracing() {
sTracingEnabled = true;
}
// 禁用Binder IPC跟踪。
public static void disableTracing() {
sTracingEnabled = false;
}
// 检查binder事务跟踪是否被使能。
public static boolean isTracingEnabled() {
return sTracingEnabled;
}
// 获取该进程的binder事务跟踪器。
public synchronized static TransactionTracker getTransactionTracker() {
if (sTransactionTracker == null)
sTransactionTracker = new TransactionTracker();
return sTransactionTracker;
}
// 获取该进程的binder事务观察者。
public static void setObserver(@Nullable BinderInternal.Observer observer) {
sObserver = observer;
}
static volatile boolean sWarnOnBlocking = false;
// 如果这个进程阻塞了binder事务,则发出警告。通常仅对系统进程有用,以防止其阻塞对外部不受信任代码的调用。
// 相反,所有需要结果的传出调用必须以IBinder#FLAG_ONEWAY调用的形式发送,这些调用通过回调接口传递结果。
public static void setWarnOnBlocking(boolean warnOnBlocking) {
sWarnOnBlocking = warnOnBlocking;
}
// 允许对给定接口进行阻塞调用,覆盖setWarnOnBlocking(boolean)所请求的值。
// 只有当完全确定远程接口是一个永远无法升级的内置系统组件时,才应很少调用该接口。
// 这个绝不能被可以被升级或替换的包托管的接口调用,否则,如果远程接口卡住,将面临系统不稳定的风险。
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}
// 将给定的接口重置回默认的阻塞行为,还原allowBlocking(IBinder)所做的任何更改。
public static IBinder defaultBlocking(IBinder binder) {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = sWarnOnBlocking;
}
return binder;
}
// 从一个给定接口继承当前allowBlocking(IBinder)的值到另一个接口。
public static void copyAllowBlocking(IBinder fromBinder, IBinder toBinder) {
if (fromBinder instanceof BinderProxy && toBinder instanceof BinderProxy) {
((BinderProxy) toBinder).mWarnOnBlocking = ((BinderProxy) fromBinder).mWarnOnBlocking;
}
}
// 指向JavaBBinderHolder对象的原始native指针。Java对象所拥有。不为空。
@UnsupportedAppUsage
private final long mObject;
private IInterface mOwner;
private String mDescriptor;
// 返回发送当前正在处理事务的进程ID。如果当前线程未在执行时传入事务,则返回其自己的pid。
// 该pid可以与更高级别的系统服务一起使用,以确定其身份并检查权限。
@CriticalNative
public static final native int getCallingPid();
// 返回分配给发送当前正在处理事务的进程uid。如果当前线程未在执行时传入事务,则返回其自己的uid。
// 该uid可以与更高级别的系统服务一起使用,以确定其身份并检查权限。
@CriticalNative
public static final native int getCallingUid();
// 如果当前线程正在执行传入事务,则返回true。
@CriticalNative
public static final native boolean isHandlingTransaction();
// 返回分配发送当前正在处理事务的进程uid。
// 如果当前线程未在执行传入事务,则抛出IllegalStateException。
public static final int getCallingUidOrThrow() {
if (!isHandlingTransaction()) {
throw new IllegalStateException(
"Thread is not in a binder transcation");
}
return getCallingUid();
}
// 返回分配给已发送当前正在处理事务的进程UserHandle。这是调用者的用户。
// 它与getCallingUid()的不同之处在于,特定用户将在其下运行多个不同的应用程序,每个应用程序都有自己的uid。
// 如果当前线程未在执行传入事务,则返回其自己的UserHandle。
public static final @NonNull UserHandle getCallingUserHandle() {
return UserHandle.of(UserHandle.getUserId(getCallingUid()));
}
// 重置传入当前线程IPC身份。如果在处理传入调用时,将要在进程本地的其他对象的接口上进行调用;
// 并且需要对进入它们的调用进行权限检查(因此它们将检查本地进程的权限,而不是最初调用的进程权限)。
// 返回一个token,该token可以通过将其传递给restoreCallingIdentity(long)来还原原始的调用身份。
@CriticalNative
public static final native long clearCallingIdentity();
// 将传入当前线程的IPC身份还原回clearCallingIdentity返回的先前身份。
// 参数token:token先前由clearCallingIdentity返回的。
public static final native void restoreCallingIdentity(long token);
// 运行clearCallingIdentity/restoreCallingIdentity中提供操作的便利方法。
// 调用restoreCallingIdentity后,将捕获给定操作抛出的任何异常并重新抛出。
public static final void withCleanCallingIdentity(@NonNull ThrowingRunnable action) {
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
action.runOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
} finally {
restoreCallingIdentity(callingIdentity);
if (throwableToPropagate != null) {
throw ExceptionUtils.propagate(throwableToPropagate);
}
}
}
// 用于运行包含在clearCallingIdentity/restoreCallingIdentity中提供的操作的便捷方法。
// 该方法返回结果调用restoreCallingIdentity}后,将捕获并重新抛出由给定操作引发的任何异常
public static final <T> T withCleanCallingIdentity(@NonNull ThrowingSupplier<T> action) {
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
return action.getOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
return null;
} finally {
restoreCallingIdentity(callingIdentity);
if (throwableToPropagate != null) {
throw ExceptionUtils.propagate(throwableToPropagate);
}
}
}
// 设置native本地线程StrictMode策略掩码。
// StrictMode设置保存在两个位置:用于libcore/Dalvik的Java级线程本地,和用于通过Binder调用传输的本地线程本地(在此设置)。
@CriticalNative
public static final native void setThreadStrictModePolicy(int policyMask);
// 获取当前native本地线程StrictMode策略掩码。
@CriticalNative
public static final native int getThreadStrictModePolicy();
// 设置该线程的工作源。
// 如果在正在进行的binder事务期间调用了此方法,则以下所有binder调用都将使用工作源,直到事务结束。
// 工作源的概念类似于WorkSource。但是,出于性能原因,仅支持一个UID。该UID代表负责binder调用的原始用户。
// restoreCallingWorkSource(long)必须在设置工作源之后始终被调用。
// 将传输工作源,以供将来在此线程上执行的外发binder事务处理。
// 参数workSource:负责binder调用的原始UID。
// 返回token,可还原原始工作源。
@CriticalNative
public static final native long setCallingWorkSourceUid(int workSource);
// 返回调用者设置的工作源。
@CriticalNative
public static final native int getCallingWorkSourceUid();
// 清除该线程的工作源。将传播工作源,以供将来在此线程上执行的外发binder事务。
@CriticalNative
public static final native long clearCallingWorkSource();
// 使用setCallingWorkSourceUid(int)或clearCallingWorkSource()返回的token在此线程上还原工作源。
@CriticalNative
public static final native void restoreCallingWorkSource(long token);
// 标记为稳定性的VINTF。该API仅应由编译系统调用。
// 这意味着可以保证由此binder表示的接口可以保持稳定一些年,并且编译系统还保留这些API的快照并调用AIDL编译器以确保这些快照向后兼容。
// 可用VintfStability接口代替使用此API。
public final native void markVintfStability();
// 将当前线程中所有待处理的Binder命令烧写到内核驱动程序。
// 在执行可能会长时间阻塞的操作之前调用此方法很有用,以确保释放了所有待处理的对象引用,以防止该过程将对象保留的时间超过所需时间。
public static final native void flushPendingCommands();
// 将调用线程添加到IPC线程池。在当前进程退出之前,该函数不会返回。
public static final void joinThreadPool() {
BinderInternal.joinThreadPool();
}
// 如果指定的接口是代理,则返回true。
public static final boolean isProxy(IInterface iface) {
return iface.asBinder() != iface;
}
// 直到执行的binder线程数小于该进程允许的最大binder线程数调用阻塞。
public static final native void blockUntilThreadAvailable();
// 默认构造器只是初始化该对象。
// 如果要创建Binder token(没有附加接口的Binder对象),则应改用Binder(String)。
public Binder() {
this(null);
}
// 用于创建原始Binder对象(token)和描述符的构造函数。binder对象的描述符通常指定它们正在实现的接口。
// 如果使用binder令牌,则不会实现任何接口,并且描述符可以用作一种标签来帮助识别binder token。这将有助于在调试时更轻松地标识对这些对象的远程引用。
// 参数descriptor:用于标识此token的创建者,例如类名。
public Binder(@Nullable String descriptor) {
mObject = getNativeBBinderHolder();
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject);
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Binder> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mDescriptor = descriptor;
}
// 用于将特定接口与Binder关联的便捷方法。调用之后,将实现queryLocalInterface(),以便在请求相应的描述符时返回给定的所有者IInterface。
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
// 默认实现。返回一个空的接口名。
public @Nullable String getInterfaceDescriptor() {
return mDescriptor;
}
// 默认实现,总是返回true,说明对象处于存活状态。
public boolean pingBinder() {
return true;
}
// 如果正在调用本地binder,则始终返回true,因为如果正在调用它,则该进程仍处于活动状态。
public boolean isBinderAlive() {
return true;
}
// 如果提供的信息与请求的描述符匹配,请使用attachInterface()提供的信息来返回关联的IInterface。
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
// 控制在此过程中禁用dump调用。当系统进程监视程序检测到系统已挂起并将其报告回activity控制器时,系统进程监视程序使用它禁用传入的dump调用。
// 这是为了防止控制器此时挂断错误报告。
// 参数msg:显示消息而不是dump; 如果为null,则重新启用dump。
public static void setDumpDisabled(String msg) {
sDumpDisabled = msg;
}
// 代理侧每个binder调用通知监听器。
@SystemApi
public interface ProxyTransactListener {
// 在onTransact之前调用。
// 将传递回#onTransactEnded的对象(或null)。
@Nullable
Object onTransactStarted(@NonNull IBinder binder, int transactionCode);
// 在onTransact之后调用(即便抛出了异常)。
// 参数session:onTransactStarted返回的对象。
void onTransactEnded(@Nullable Object session);
}
// 将工作源传给system server执行的binder调用。
// 默认情况下,如果传出调用与传入的binder调用发生在同一线程上,则此监听器将传输工作源。
// 可以通过调用ThreadLocalWorkSource的setUid(int)来完成自定义归因。
public static class PropagateWorkSourceTransactListener implements ProxyTransactListener {
@Override
public Object onTransactStarted(IBinder binder, int transactionCode) {
// 改用ThreadLocalWorkSource。它还允许功能所有者手动设置ThreadLocalWorkSource的set(int)方法来将资源分配给UID。
int uid = ThreadLocalWorkSource.getUid();
if (uid != ThreadLocalWorkSource.UID_NONE) {
return Binder.setCallingWorkSourceUid(uid);
}
return null;
}
@Override
public void onTransactEnded(Object session) {
if (session != null) {
long token = (long) session;
Binder.restoreCallingWorkSource(token);
}
}
}
// 设置一个代理侧事务的监听器。该监听器是全局性的,只有快操作才能避免线程竞争现象。
// 监听器需要能处理同步操作,即可以并发调用监听器方法。
// 监听器集将用于新事务。正在进行的事务仍将使用以前的监听器(若曾设置过监听器)。
// 在binder事务的关键路径上调用了监听器,因此需要关注性能。不要在监听器内执行其他binder事务。
@SystemApi
public static void setProxyTransactListener(@Nullable ProxyTransactListener listener) {
BinderProxy.setTransactListener(listener);
}
// 默认实现是一个stub,它返回false。将覆盖此内容以进行适当的事务编组。如果要调用此函数,需调用transact()。
// 返回结果的实现通常应使用Parcel.writeNoException和Parcel.writeException将异常传回调用方。
// 第一个参数code:要执行的动作。这应该是FIRST_CALL_TRANSACTIONLAST_CALL_TRANSACTION之间的数字。
// 第二个参数data:正在从调用方接收到编组数据。
// 第三个参数reply:如果调用者期望返回结果,则应将其整理到此处。
// 第四个参数flags:附加操作标志。对于普通RPC,选择0;对于单向RPC,使用FLAG_ONEWAY。
// 返回值:成功调用返回true;返回false通常用于表示不了解事务码。
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if (code == INTERFACE_TRANSACTION) {
reply.writeString(getInterfaceDescriptor());
return true;
} else if (code == DUMP_TRANSACTION) {
ParcelFileDescriptor fd = data.readFileDescriptor();
String[] args = data.readStringArray();
if (fd != null) {
try {
dump(fd.getFileDescriptor(), args);
} finally {
IoUtils.closeQuietly(fd);
}
}
// 写StrictMode头。
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
return true;
} else if (code == SHELL_COMMAND_TRANSACTION) {
ParcelFileDescriptor in = data.readFileDescriptor();
ParcelFileDescriptor out = data.readFileDescriptor();
ParcelFileDescriptor err = data.readFileDescriptor();
String[] args = data.readStringArray();
ShellCallback shellCallback = ShellCallback.CREATOR.createFromParcel(data);
ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
try {
if (out != null) {
shellCommand(in != null ? in.getFileDescriptor() : null,
out.getFileDescriptor(),
err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
args, shellCallback, resultReceiver);
}
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(err);
// 写StrictMode头。
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
}
return true;
}
return false;
}
// 将事务代码解析为易于理解的名称。默认实现是一个返回null的存根。
// AIDL生成的代码将返回原始方法名称。
// 参数transactionCode:要解析的代码。
public @Nullable String getTransactionName(int transactionCode) {
return null;
}
// 实现调用更方便的版本。
public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) {
FileOutputStream fout = new FileOutputStream(fd);
PrintWriter pw = new FastPrintWriter(fout);
try {
doDump(fd, pw, args);
} finally {
pw.flush();
}
}
void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
final String disabled = sDumpDisabled;
if (disabled == null) {
try {
dump(fd, pw, args);
} catch (SecurityException e) {
pw.println("Security exception: " + e.getMessage());
throw e;
} catch (Throwable e) {
// 与通常的调用不同,在这种情况下,如果抛出异常,将其打印回dump数据中,因为调用者希望在那里收集所有有用的信息。
pw.println();
pw.println("Exception occurred while dumping:");
e.printStackTrace(pw);
}
} else {
pw.println(sDumpDisabled);
}
}
// 类似于dump(FileDescriptor,String[]),但要确保目标是异步执行的。
public void dumpAsync(@NonNull final FileDescriptor fd, @Nullable final String[] args) {
final FileOutputStream fout = new FileOutputStream(fd);
final PrintWriter pw = new FastPrintWriter(fout);
Thread thr = new Thread("Binder.dumpAsync") {
public void run() {
try {
dump(fd, pw, args);
} finally {
pw.flush();
}
}
};
thr.start();
}
// 将对象的状态打印到给定的流中。
// 第一个参数fd:将dump发送到的原始文件描述符。
// 第二个参数fout:应将状态dump到的文件。
// 第三个参数args:为dump请求添加其他参数。
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {
}
// 在这个对象上执行一个shell命令。这可以从调用者异步执行; 完成时,实现必须始终调用resultReceiver。
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback callback,
@NonNull ResultReceiver resultReceiver) throws RemoteException {
onShellCommand(in, out, err, args, callback, resultReceiver);
}
// 处理对shellCommand的调用。默认实现只是打印一条错误消息。覆盖并替换为您自己的。
// 在调用此方法之前,不进行权限检查; 必须对正在执行的命令进行适当的安全检查。
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback callback,
@NonNull ResultReceiver resultReceiver) throws RemoteException {
FileOutputStream fout = new FileOutputStream(err != null ? err : out);
PrintWriter pw = new FastPrintWriter(fout);
pw.println("No shell command implementation.");
pw.flush();
resultReceiver.send(0, null);
}
// 默认实现倒回parcels并在onTransact上调用。在远端,事务将调用binder以进行IPC。
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
// 本地实现是不可操作的。
public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
}
// 本地实现是不可操作的。
public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
return true;
}
static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
// 尝试发送大于800k数据。
StringBuilder sb = new StringBuilder();
sb.append(msg);
sb.append(": on ");
sb.append(obj);
sb.append(" calling ");
sb.append(code);
sb.append(" size ");
sb.append(parcel.dataSize());
sb.append(" (data: ");
parcel.setDataPosition(0);
sb.append(parcel.readInt());
sb.append(", ");
sb.append(parcel.readInt());
sb.append(", ");
sb.append(parcel.readInt());
sb.append(")");
Slog.wtfStack(TAG, sb.toString());
}
}
private static native long getNativeBBinderHolder();
private static native long getFinalizer();
// 默认情况下,使用调用uid,因为它始终可信。
private static volatile BinderInternal.WorkSourceProvider sWorkSourceProvider =
(x) -> Binder.getCallingUid();
// 设置工作源提供者。回调是全局的。只有快速操作才能避免线程竞争。
// 如果需要,回调实现需要处理同步。回调中的方法可以并发调用。
// 回调是在活页夹事务的关键路径上调用的,因此要注意性能。不可在回调内部执行其他binder事务。
public static void setWorkSourceProvider(BinderInternal.WorkSourceProvider workSourceProvider) {
if (workSourceProvider == null) {
throw new IllegalArgumentException("workSourceProvider cannot be null");
}
sWorkSourceProvider = workSourceProvider;
}
// android_util_Binder.cpp的onTransact函数的入口。
@UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
// 此时,尚未解析parcel请求头,因此不知道调用者设置了哪个WorkSource。使用调用uid作为默认值。
final int callingUid = Binder.getCallingUid();
final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid);
try {
return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
}
}
private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
int callingUid) {
// 确保观察者在处理事务时不会改变。
final BinderInternal.Observer observer = sObserver;
final CallSession callSession =
observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null;
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
// 从理论上讲,应该调用事务处理,该方法将调用onTransact,但所做的只是回调它,因此将直接调用它。
boolean res;
// 将异常记为警告,如果调用是FLAG_ONEWAY,则这些异常会消失。
final boolean tracingEnabled = Binder.isTracingEnabled();
try {
if (tracingEnabled) {
final String transactionName = getTransactionName(code);
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, getClass().getName() + ":"
+ (transactionName != null ? transactionName : code));
}
res = onTransact(code, data, reply, flags);
} catch (RemoteException|RuntimeException e) {
if (observer != null) {
observer.callThrewException(callSession, e);
}
if (LOG_RUNTIME_EXCEPTION) {
Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
}
if ((flags & FLAG_ONEWAY) != 0) {
if (e instanceof RemoteException) {
Log.w(TAG, "Binder call failed.", e);
} else {
Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
}
} else {
// 在写入异常之前清除parcel。
reply.setDataSize(0);
reply.setDataPosition(0);
reply.writeException(e);
}
res = true;
} finally {
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
if (observer != null) {
// 在onTransact期间已调用了parcel RPC标头,因此现在可以从parcel中访问工作源uid。
final int workSourceUid = sWorkSourceProvider.resolveWorkSourceUid(
data.readCallingWorkSourceUid());
observer.callEnded(callSession, data.dataSize(), reply.dataSize(), workSourceUid);
}
}
checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
reply.recycle();
data.recycle();
// 已经完成了IPC,所以应该没有更多的严格的模式冲突聚集在该线程上。
// 它们要么已被打包,现在正被转移到调用方,要么将返回主事务循环以等待另一个传入事务。无论哪种方式,都会属于strict mode!
StrictMode.clearGatheredViolations();
return res;
}
// 从servicemanager返回指定的服务。如果服务未运行,则servicemanager将尝试启动它,并且此功能将等待其准备就绪。
// 仅当存在权限问题或致命错误时才返回nullptr。
public static final native @Nullable IBinder waitForService(@NonNull String serviceName)
throws RemoteException;
}