clearCallingIdentity与restoreCallingIdentity-千里马framework系统源码实战详解

93 篇文章 58 订阅
90 篇文章 66 订阅

hi,粉丝朋友大家好:
今天带大家来学习一个系统开发过程中大家即“熟悉”又陌生的两个方法,分别是clearCallingIdentity和restoreCallingIdentity,一般他们是成对出现在我们的framework代码中,但大家平时分析源码时候好像并没有在意他的真正作用是什么?为啥在框架代码分析时候可以看到他的大量出现?
重点更多干货看这里:
https://blog.csdn.net/learnframework/article/details/127483545

大家来看一个经典案例:
假如我们在ActivityManagerService加入一个接口方法:

@Override
public void testClear() {
    Settings.Global.putString(
            resolver, Settings.Global.DEBUG_APP,
            packageName);
}

接口方法里面执行时候需要调用到Setting相关方法,app调用该接口app自身没有Setting权限,想抱SystemServer大腿,咋一看感觉没有问题,因为testClear方法已经运行在SystemServer进程,该进程肯定有Settings相关权限,但事实真的如此么?
事实上执行会报如下错误:
Package android does not belong to xxxxx

这个是为啥?
其实这类问题出现就和权限判断方式有关系,一般权限判断都是会通过类似
Binder.getCallingUid来获取我们的调用段的uid也就是获取了调用包名,然后通过包名查询到底是否有权限操作。。。方式,所以这里出现错误也就不奇怪,那么这问题怎么解决呢?那就我们今天主题clearCallingIdentity和restoreCallingIdentity

先看clearCallingIdentity


    /**
     * Reset the identity of the incoming IPC on the current thread.  This can
     * be useful if, while handling an incoming call, you will be calling
     * on interfaces of other objects that may be local to your process and
     * need to do permission checks on the calls coming into them (so they
     * will check the permission of your own local process, and not whatever
     * process originally called you).
     *
     * @return Returns an opaque token that can be used to restore the
     * original calling identity by passing it to
     * {@link #restoreCallingIdentity(long)}.
     *
     * @see #getCallingPid()
     * @see #getCallingUid()
     * @see #restoreCallingIdentity(long)
     */
    @CriticalNative
    public static final native long clearCallingIdentity();

再看restoreCallingIdentity

  /**
     * Restore the identity of the incoming IPC on the current thread
     * back to a previously identity that was returned by {@link
     * #clearCallingIdentity}.
     *
     * @param token The opaque token that was previously returned by
     * {@link #clearCallingIdentity}.
     *
     * @see #clearCallingIdentity
     */
    @CriticalNative
    public static final native void restoreCallingIdentity(long token);

//clearCallingIdentity具体实现

static jlong android_os_Binder_clearCallingIdentity()
{
    return IPCThreadState::self()->clearCallingIdentity();
}
int64_t IPCThreadState::clearCallingIdentity()
{
    // ignore mCallingSid for legacy reasons
    int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
    clearCaller();
    return token;//注意这里记忆了原来的mCallingUid mCallingPid
}
void IPCThreadState::clearCaller()
{
    mCallingPid = getpid();
    mCallingSid = nullptr;  // expensive to lookup
    mCallingUid = getuid();
}

其注释其实已经讲解比较清楚了,就是在IPC跨进程调用过程中,可能会调用到其他对象相关方法,这些相关方法可能会有权限的校验,一旦你调用了clearCallingIdentity相当于就是服务端进程自己调用了
其实本质上clearCallingIdentity方法就干了一件事:
当前调用线程后面调用getCallingUid的值变成自己进程的UID,那么后面调用其他方法如果需要权限,那么就判断是服务进程是否有权限,这里也就说明systemserver为啥用的比较多clearCallingIdentity,因为systemserver相对具体很多权限,本身很多功能就是他定义的,但各个app权限相对很少,就会经常产生抱大腿思路

restoreCallingIdentity其实本质就是对前面clearCallingIdentity后,需要对当前线程的UID进行恢复,因为不可能一直让调用使用自己uid,有的地方业务场景是需要真实uid的,所以这个clearCallingIdentity一般都是在需要权限校验方法才会使用,权限过了执行完毕是需要及时恢复的。
所以就clearCallingIdentity和restoreCallingIdentity经常成对出现原因。

解决方法:

@Override
public void testClear() {
  final long ident = Binder.clearCallingIdentity();
    Settings.Global.putString(
            resolver, Settings.Global.DEBUG_APP,
            packageName);
    Binder.restoreCallingIdentity(ident);
}

以上进行clear和restore后既可以正常执行
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值