背景:
上一篇文章给大家布置了一个binder面试题相关的作业,具体看如下文章:
这个binder面试题你会吗?-学员作业
很多同学也对这个callingpid为0的情况感觉到很奇怪,也不太清楚为啥。

最后的作业要求一共就3个部分:
1、剖析出uid和pid是如何在kernel中被binder驱动进行设置的
2、解释什么场景调用pid就会设置为0
3、解释清楚为啥同样的captureDisplay接口,aosp14和aosp16会有差异。
下面本文将对上面3个疑问进行挨个剖析讲解清楚。

CallingUid,Pid的数据来源分析
先看看场景调用getCallingPid,getCallingUid对应的值:
pid_t IPCThreadState::getCallingPid() const
{
checkContextIsBinderForUse(__func__);
return mCallingPid;
}
uid_t IPCThreadState::getCallingUid() const
{
checkContextIsBinderForUse(__func__);
return mCallingUid;
}
那么这里的mCallingPid,mCallingUid是在哪里进行的赋值呢?
这块经过寻找发现是在executeCommand方法中BR_TRANSACTION时候进行的赋值。
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
//省略部分
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
binder_transaction_data_secctx tr_secctx;
binder_transaction_data& tr = tr_secctx.transaction_data;
if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
result = mIn.read(&tr_secctx, sizeof(tr_secctx));
} else {
result = mIn.read(&tr, sizeof(tr));
tr_secctx.secctx = 0;
}
mCallingPid = tr.sender_pid;
mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
mCallingUid = tr.sender_euid;
可以看到这里的赋值来源就是binder驱动中传递过来的sender_pid,sender_euid。
kernel中分析CallingUId和Pid的设置
通过对比发现无论aosp14还是aosp16在kernel这块对sender_pid和sender_euid的设置代码都是一样的,所以对于kernel这块都是使用一份代码就可以。
发起跨进程调用会执行到binder_transaction方法中,这里会创建对应的binder_transaction,而且会给binder_transaction进行相关的赋值,然后到目标进程的binder_thread_read进行使用
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size)
{
//省略部分
//可以看到这里会对flag进行判断,如果不是ONE_WAY调用那么就会赋值thread,如果ONE_WAY那就赋值NULL
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
else
t->from = NULL;
t->from_pid = proc->pid;
t->from_tid = thread->pid;
//这里直接赋值调用进程的uid
t->sender_euid = task_euid(proc->tsk);
在目标进程binder_thread_read方法中,会读取上面的对sender_pid和sender_euid进行设置,返回到app层面
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
//省略部分
trd->flags = t->flags;
trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid);
t_from = binder_get_txn_from(t);
if (t_from) {
struct task_struct *sender = t_from->proc->tsk;
trd->sender_pid =
task_tgid_nr_ns(sender,
task_active_pid_ns(current));
trace_android_vh_sync_txn_recvd(thread->task, t_from->task);
} else {
trd->sender_pid = 0;
}
通过查看binder驱动中源码,得出以下结论:
1、sender_euid的值就是发起binder调用的进程对于uid值
2、对于sender_pid这块需要考虑2种情况。
a、binder调用是oneway(异步调用)情况那就是pid = 0
b、如果调用是同步的,非oneway情况,那么pid就是原来进程的pid值。
那么到此就回答了昨天面试题作业的前2问,剩下最后一问:
解释清楚为啥同样的captureDisplay接口,aosp14和aosp16会有差异。
那么下面重点来分析这块14,16的差异。
aosp16与aosp14上captureLayers接口对比
首先从binder驱动部分源码可以看出,影响pid最核心的参数就是传递进来的flag
drivers/android/binder.c
这个flag本质是app层面在IPCThreadStated的transact调用时候进行传递的。
可以看到这里还有log进行打印,但是一般默认这个log不开放,这里需要去修改开放:

然后在日志调查:
aosp16打印发现属于同步跨进程调用
12-25 11:40:03.197 487 719 D WindowManager: captureDisplay
12-25 11:40:03.197 487 719 D ipc : >>>> SEND from pid 487 uid 1000 READ REPLY
aosp16打印发现属于oneway这种异步跨进程调用
12-24 11:40:47.892 751 1135 D WindowManager: captureDisplay 10150 pid 0
12-24 11:40:47.892 751 1135 D ipc : >>>> SEND from pid 751 uid 1000 ONE WAY
也可以抓一下2个版本对于的Perfetto进行分析
aosp14上captureLayers是同步跨进程调用方式:

aosp16上captureLayers是异步跨进程调用方式,也就是oneway方式:

最后看看aidl文件:
aosp14这个captureLayers接口:
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
* This requires READ_FRAME_BUFFER permission. This function will fail if there
* is a secure window on screen
*/
void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
aosp16这个captureLayers接口确实oneway:
frameworks/native/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
* This requires READ_FRAME_BUFFER permission. This function will fail if there
* is a secure window on screen
*/
oneway void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
到此你应该可以把这个一波三折的binder面试题得到满分了吧。
原文地址:
https://mp.weixin.qq.com/s/6iiNNzq_37g_wS8dNOqRzw
更多framework实战开发干货,请关注下面“千里马学框架”
1645

被折叠的 条评论
为什么被折叠?



