clearCallingIdentity与restoreCallingIdentity-千里马framework系统源码实战详解
Posted learnframework
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了clearCallingIdentity与restoreCallingIdentity-千里马framework系统源码实战详解相关的知识,希望对你有一定的参考价值。
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后既可以正常执行
以上是关于clearCallingIdentity与restoreCallingIdentity-千里马framework系统源码实战详解的主要内容,如果未能解决你的问题,请参考以下文章