【Android】Binder傳送檔案描述符分析
在進行dumpsys呼叫的時候,dump方法的第一個引數是檔案描述符
BinderProxy.java
publicvoid dump(FileDescriptor fd, String[] args)通過傳送檔案描述符來讓服務端向給定的檔案寫資料,
等等,仔細想想,好像有什麼不對
是啊,每個程序中的檔案描述符是獨立無關的,你把C程序中的檔案描述符傳給S程序,這不是刻舟求劍麼?
但是,Android的binder看上去就是傳送了檔案描述符,這裡面暗藏了什麼玄機呢?
我們在讀寫檔案描述符的地方加上log
{
int dupFd = dup(fd);
if(dupFd < 0) {
return -errno;
}
//在這裡新增log,檢視fd的值
ALOGE("writeDupFileDescriptor: fd = %d, dupfd = %d\n", fd, dupFd);
if (err) {
close(dupFd);
}
return err;
}
{
if (
ALOGD("00 ========== android_os_Parcel_readFileDescriptor, fd=%d", fd);
if (fd < 0) returnNULL;
fd = dup(fd);
ALOGD("========== android_os_Parcel_readFileDescriptor, fd=%d", fd);
if (fd < 0) return NULL;
}
return NULL;
}
進行一次dump呼叫,檢視log
我們會發現,寫入的fd和服務端讀出的fd不一樣,但是服務端卻正確的完成了資料的輸出,為什麼呢?
肯定有地方進行了處理。
通過檢視,我們發現,原來是在資料傳輸的過程中被做了手腳,binder驅動在傳送資料的時候,在服務端上建立了一個新的fd,並且把這個fd和客戶端fd所對應的檔案進行了關聯。
處理流程
BinderProxy.java
public void dump(FileDescriptor fd,String[] args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeFileDescriptor(fd);
data.writeStringArray(args);
try {
transact(DUMP_TRANSACTION, data,reply, 0);
reply.readException();
} finally {
data.recycle();
reply.recycle();
}
}
呼叫到
Parcel.java
public final void writeFileDescriptor(FileDescriptor val) {
updateNativeSize(nativeWriteFileDescriptor(mNativePtr,val));
}
frameworks/base/core/jni/android_util_Binder.cpp
staticjboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobjectreplyObj, jint flags) // throws RemoteException
{
frameworks/native/libs/binder/BpBinder.cpp
status_tBpBinder::transact(
uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will nevercome back to life.
if (mAlive) {
status_t status =IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
./frameworks/native/libs/binder/IPCThreadState.cpp
status_tIPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel*reply, uint32_t flags)
{
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr" << (void*)pthread_self() << " / hand "
<< handle << " /code " << TypeCode(code) << ": "
<< indent << data<< dedent << endl;
}
if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SENDfrom pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ?"READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle,code, data, NULL);
}
… …
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err =waitForResponse(&fakeReply);
}
status_tIPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
#ifdef_MTK_ENG_BUILD_
cmd = 0;// initialze it for build error[-Werror=maybe-uninitialized]
#endif
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
status_tIPCThreadState::talkWithDriver(bool doReceive)
{
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ,&bwr) >= 0)
然後呼叫到binder驅動裡最終,呼叫到方法binder_transaction
在裡面對fd進行了處理
kernel-3.18/drivers/staging/android/binder.c
static void binder_transaction(structbinder_proc *proc,
structbinder_thread *thread,
structbinder_transaction_data *tr, int reply)
{
… …
case BINDER_TYPE_FD:{
int target_fd;
struct file *file;
if (reply) {
if(!(in_reply_to->flags & TF_ACCEPT_FDS)) {
binder_user_error
("%d:%dgot reply with fd, %d, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
} else if(!target_node->accept_fds) {
binder_user_error
("%d:%d got transaction with fd, %d, but target does not allowfds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
gotoerr_fd_not_allowed;
}
//根據檔案描述符獲取到其對應的檔案資訊
//在某些Unix系統中,該方法名是getf
file =fget(fp->handle);
if (file ==NULL) {
binder_user_error
("%d:%d got transaction with invalid fd, %d\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
gotoerr_fget_failed;
}
if(security_binder_transfer_file
(proc->tsk, target_proc->tsk, file) < 0) {
fput(file);
return_error = BR_FAILED_REPLY;
goto err_get_unused_fd_failed;
}
//在目標程序中獲取一個沒有使用的檔案描述符
target_fd =task_get_unused_fd_flags(target_proc, O_CLOEXEC);
if (target_fd< 0) {
fput(file);
return_error = BR_FAILED_REPLY;
gotoerr_get_unused_fd_failed;
}
//把目標程序中新建的fd和file資訊關聯起來,實現了程序間fd的複製
task_fd_install(target_proc, target_fd, file);
trace_binder_transaction_fd(t, fp->handle, target_fd);
binder_debug(BINDER_DEBUG_TRANSACTION,
" fd %d -> %d\n", fp->handle,target_fd);
/* TODO: fput?*/
fp->binder =0;
fp->handle = target_fd;
#ifdefBINDER_MONITOR
e->fd =target_fd;
#endif
}
break;
相關推薦
【Android】Binder傳送檔案描述符分析
在進行dumpsys呼叫的時候,dump方法的第一個引數是檔案描述符 BinderProxy.java publicvoid dump(FileDescriptor fd, String[] args) 通過傳送檔案描述符來讓服務端向給定的檔案寫資料, 等等,仔
【Android】dumpsys為什麼要傳送檔案描述符
突然間想起一個問題:dumpsys為什麼要傳送檔案描述符 而不採用獲取返回字串,然後再進行列印呢? 考慮了下,發現傳送檔案描述符這個大招確實很妙。 1. dump列印的資訊有時候很大,而binder不適合傳送大量的資料,binder驅動中分配的空間也是有限的
android程序間傳遞檔案描述符原理
在linux中,程序開啟一個檔案,返回一個整數的檔案描述符,然後就可以在這個檔案描述符上對該檔案進行操作。那麼檔案描述符和檔案到底是什麼關係?程序使用的是虛擬地址,不同程序間是地址隔離的,如何在兩個程序中傳遞檔案描述符,然後指向同一檔案(binder傳遞檔案描述符)? li
【Android】 XML佈局檔案中,使用自定義屬性不提示和不生效
在XML檔案中使用首先要宣告 xmlns:toolbar=http://schemas.android.com/apk/res/cn.zzm.toolbar 注意,“toolbar”可以換成其他的任何名字,後面的url地址必須最後一部分必須用上自定義元件的包名。自定義屬性了
【android】各映象檔案img介紹
Android 原始碼編譯後,在out/target/product/generic下生成的三個映象檔案:ramdisk.img,system.img,userdata.img以及它們對應的目錄root,system,data。 ramdisk.img是根檔案
【android】點選touch事件流程分析
1、onTouch和onTouchEvent的區別 public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && mOnTouch
【Java】基礎:常見修飾符(權限修飾符以及abstract、static、final等)與變量的描述
線程 cte string 數據 執行 style 權限 實例 類名 1. 修飾符 public、protected、private、default abstract、static、final、 abstract:抽象類、抽象方法 static:靜態變量、
【Android】刪除已知路徑的檔案或資料夾
轉載請註明出處,原文連結:https://blog.csdn.net/u013642500/article/details/80153517 【功能】 delete(String delFile):刪除檔案或資料夾 deleteSingleFile(String fil
【Android】複製assets裡的單檔案到指定資料夾
轉載請註明出處,原文連結:https://blog.csdn.net/u013642500/article/details/80069811 本方法使用前提是已擁有許可權,未對許可權不足情況進行處理,如有需要可自行新增。 關於讀寫許可權的總結請參考:https://blog.csdn.n
【Android】【系統】Android檔案目錄結構
system/app:存放系統軟體 system/data:存放系統軟體的資料 data/app:存放使用者安裝的軟體 data/data:存放使用者軟體的資料 storage/emulated/0:儲存卡 storage/sdcard:虛擬路徑,快捷方式,實際
【Android】獲取手機中已安裝apk檔案資訊(PackageInfo、ResolveInfo)(應用圖片、應用名、包名等)
眾所周知,通過PackageManager可以獲取手機端已安裝的apk檔案的資訊,具體程式碼如下 PackageManager packageManager = this.getPackageManager(); List<PackageInfo> pac
【Android】檔案儲存-內部儲存
Table of Contents 檔案的操作模式 儲存資料 讀取資料 檔案的操作模式 MODE_PRIVATE:該檔案只能被當前程式讀寫 MODE_APPEND:該檔案的內容可以追加 MODE_WORLD_READABLE:可
【Android】專案中資料夾和檔案的作用
Table of Contents 資料夾的作用 檔案的作用 資料夾的作用 No. 資料夾 描述 1 src 存放
【Android】app打包成apk檔案以後,如何檢視VersionCode、VersionName等版本資訊
Android App打包成Apk後,其實是一個壓縮檔案,可以將字尾名apk改為zip然後用winrar開啟也能看到裡面的檔案結構。還能看到AndroidManifest.xml。但是裡面的內容經過編碼顯示為亂碼,不方便檢視。 aapt工具:
【android】簡易檔案管理器(列表式檔案目錄)
、 核心程式碼: File fatherFile = new File(path); File[] files = fatherFile.listFiles(); 效果圖:
【Android】GreenDao操作外部DB資料庫檔案
1.背景 所謂外部資料庫檔案此處指的就是一個在外部單獨建立的db檔案,假設有這麼一個場景,我們專案中有一些本地資料,不需要介面去獲取的(不需要進行網路操作),寫死的資料,比如全國各個省各個市的一些基本
【Android】debug 狀態下其簽名檔案 debug.keystore 相關(如何獲得該檔案,其密碼,獲取其sha1、MD5等)
Eclipse,Android studio 編譯執行 APP 的時候是生成一個 apk 的,它預設的簽名是 debug.keystore 。 有時候我們需要拿到這個簽名檔案,下面就來說說它的預設路徑: Windows下: C:\Users\<使用者名稱>\.A
【python】open函式檔案操作讀、寫和轉義符‘\n’
1、open()語法 open(file[, mode[, buffering[, encoding[, errors[, newline[, closefd=True]]]]]]) open函式使用一個檔名作為唯一的強制引數,然後返回唯一的檔案物件。 o
【Android】pull解析xml檔案+將資料儲存為xml格式,並儲存在記憶體裡
在解析中,常用到的還有一種解析就是pull去解析xml格式的檔案。事實上android內部也是這樣做的。今天這個demo是來自傳智播客,可能技術已經被翻新了。 但是基礎原理還是那樣,希望基礎學習者,能夠理解,並實際寫一寫。 首先在src目錄下匯入我們將要解析的xml檔案:
【Android】安卓佈局檔案中xmlns屬性
定義及使用 xmlns是XML Namespaces的縮寫,中文名稱是XML(標準通用標記語言的子集)名稱空間 自定義View的時候有時候會在佈局檔案中使用到 命名規則如下: xmlns:字首=http://shemas.android.com/ap