最近在看Android系統源碼,發現在源碼中有大量的方法內有Binder.clearCallingIdentity和.Binder.restoreCallingIdentity(),并且成對出現。 查資料說,大家都說是用于權限控制,不是很明白具體原理
文章出處:鏈接:https://www.zhihu.com/question/41003297/answer/89328987
**一、源碼分析**
(1)**clearCallingIdentity**方法,最終調用如下:
~~~text
int64_t IPCThreadState::clearCallingIdentity()
{
int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
clearCaller();
return token;
}
void IPCThreadState::clearCaller()
{
mCallingPid = getpid(); //當前進程pid賦值給mCallingPid
mCallingUid = getuid(); //當前進程uid賦值給mCallingUid
}
~~~
* **mCallingUid**(記為UID),保存Binder IPC通信的調用方進程的Uid;
* **mCallingPid**(記為PID),保存Binder IPC通信的調用方進程的Pid;
UID和PID是IPCThreadState的成員變量, 都是32位的int型數據,通過移位操作,將UID和PID的信息保存到token,其中高32位保存UID,低32位保存PID。然后調用clearCaller()方法將當前本地進程pid和uid分別賦值給PID和UID,最后返回token。
**一句話總結:clearCallingIdentity作用是清空遠程調用端的uid和pid,用當前本地進程的uid和pid替代;**
(2)**restoreCallingIdentity**方法,最終調用如下:
~~~text
void IPCThreadState::restoreCallingIdentity(int64_t token)
{
mCallingUid = (int)(token>>32);
mCallingPid = (int)token;
}
~~~
從token中解析出PID和UID,并賦值給相應的變量。該方法正好是clearCallingIdentity的反過程。
**一句話總結:restoreCallingIdentity作用是恢復遠程調用端的uid和pid信息,正好是`clearCallingIdentity`的反過程;**
到此,應該明白了從代碼角度是如何實現的。
**(3) 源碼示例**
上述過程主要在system\_server進程的各個線程中比較常見(普通的app應用很少出現),比如system\_server進程中的ActivityManagerService子線程,代碼如下:
\[–>ActivityManagerService.java\]
~~~text
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
//獲取遠程Binder調用端的pid
int callingPid = Binder.getCallingPid();
//清除遠程Binder調用端uid和pid信息,并保存到origId變量
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
//通過origId變量,還原遠程Binder調用端的uid和pid信息
Binder.restoreCallingIdentity(origId);
}
}
~~~
文章[startService](https://link.zhihu.com/?target=http%3A//www.yuanhh.com/2016/02/21/start-service/%23activitymanagerproxyattachapplication)中有講到attachApplication()的調用。該方法一般是system\_server進程的子線程調用遠程進程時使用,而attachApplicationLocked方法則是在同一個線程中,故需要在調用該方法前清空遠程調用者的uid和pid,調用結束后恢復遠程調用者的uid和pid。
**二、場景分析**
~~~text
場景1:首先線程A通過Binder遠程調用線程B,然后線程B通過Binder調用當前線程的另一個service或者activity之類的組件
~~~
**分析:**
1. 線程A通過Binder遠程調用線程B:則線程B的IPCThreadState中的mCallingUid和mCallingPid保存的就是線程A的UID和PID。這時在線程B中調用Binder.getCallingPid()和Binder.getCallingUid()方法便可獲取線程A的UID和PID,然后利用UID和PID進行權限比對,判斷線程A是否有權限調用線程B的某個方法。
2. 線程B通過Binder調用當前線程的某個組件:此時線程B是線程B某個組件的調用端,則mCallingUid和mCallingPid應該保存當前線程B的PID和UID,故需要調用clearCallingIdentity()方法完成這個功能。當線程B調用完某個組件,由于線程B仍然處于線程A的被調用端,因此mCallingUid和mCallingPid需要恢復成線程A的UID和PID,這是調用restoreCallingIdentity()即可完成。


一句話:圖中過程2(調用組件2開始之前)執行clearCallingIdentity(),過程3(調用組件2結束之后)執行restoreCallingIdentity()。
**二、類比分析**
看完場景分析,估計還有不少朋友感到迷惑,為何需要這兩個方法來多此一舉,直接檢測最初調用端的權限不就行了嗎?為了更加形象明了地說明其用途,下面用一個生活中的場景來類比說明。
~~~text
場景:假如你的朋友請你幫忙,給她(他)到你的公司以內部價購買公司的某個產品。
~~~
**分析:**這個過程分為兩個階段


* 第一階段:你的朋友請你幫忙的過程,這個過程并不一定所有朋友都會幫的,這時就需要一個權限檢測,那么在你的朋友”遠程調用”你執行任務時,你會記錄他的”Identity”信息(比如是性別),有了信息那么就可以權限檢測,不妨令權限規則是如果這個朋友是女性則答應幫忙,否則就認定權限不夠拒絕執行(可能黑客會想到先去一趟泰國,權限控制可能相應需要打補丁了),若答應幫忙則進入第二階段,否則直接返回。
* 第二階段:你向自己所在公司的相關部門內購產品的過程,這個過程也并不是所有人都能權限能夠內購的,只有自己公司的員工才行,否則你的朋友也不會找你幫忙了。 這個過程同樣需要權限檢測,但是”Identity”保存的是性別女的信息,公司內購產品如果也以性別來判斷,那豈不是公司的所有男員工沒有權限內購,那這公司就有點太坑了,這明顯不符合實情。 clearCallingIdentity()是時候該登場了,在第二階段開始之前,先執行clearCallingIdentity()過程,也就是把”Identity”信息清空,替換為你的信息(比如員工編碼ITCode之類的),那公司相關部門通過ITCode就可以直接判斷是否允許內購某產品。當第二階段完成后,也就是你已經購買到了公司產品,這時你需要將產品交付給你的朋友,需要restoreCallingIdentity,恢復”Identity”為女的信息,這樣就該順便交付給你的女朋友。如果不恢復信息,還是原來的ITCode,你交付的朋友可能是男的,另有其人,這樣就不科學了。
相信到此,大都能明白這兩個方法的作用,缺一不可,而且要成對出現。
- 前言
- Android系統的體系結構
- Dalvik VM 和 JVM 的比較
- Android 打包應用程序并安裝的過程
- Android ADB工具
- Android應用開發
- Android UI相關知識總結
- Android 中window 、view、 Activity的關系
- Android應用界面
- Android中的drawable和bitmap
- AndroidUI組件adapterView及其子類和Adapter的關系
- Android四大組件
- Android 數據存儲
- SharedPreference
- Android應用的資源
- 數組資源
- 使用Drawable資源
- Material Design
- Android 進程和線程
- 進程
- 線程
- Android Application類的介紹
- 意圖(Intent)
- Intent 和 Intent 過濾器(Google官網介紹)
- Android中關于任務棧的總結
- 任務和返回棧(官網譯文)
- 總結
- Android應用安全現狀與解決方案
- Android 安全開發
- HTTPS
- 安卓 代碼混淆與打包
- 動態注入技術(hook技術)
- 一、什么是hook技術
- 二、常用的Hook 工具
- Xposed源碼剖析——概述
- Xposed源碼剖析——app_process作用詳解
- Xposed源碼剖析——Xposed初始化
- Xposed源碼剖析——hook具體實現
- 無需Root也能Hook?——Depoxsed框架演示
- 三、HookAndroid應用
- 四、Hook原生應用程序
- 五、Hook 檢測/修復
- Android 應用的逆向與加固保護技術
- OpenCV在Android中的開發
- Android高級開發進階
- 高級UI
- UI繪制流程及原理
- Android新布局ConstraintLayout約束布局
- 關鍵幀動畫
- 幀動畫共享元素變換
- Android異步消息處理機制完全解析,帶你從源碼的角度徹底理解
- Android中為什么主線程不會因為Looper.loop()里的死循環卡死?
- 為什么 Android 要采用 Binder 作為 IPC 機制?
- JVM 中一個線程的 Java 棧和寄存器中分別放的是什么?
- Android源碼的Binder權限是如何控制?
- 如何詳解 Activity 的生命周期?
- 為什么Android的Handler采用管道而不使用Binder?
- ThreadLocal,你真的懂了嗎?
- Android屏幕刷新機制