2012-01-24 31 views
4

有人可以指點我有關android應用程序框架開發的教程嗎?在這裏,我特別提到「應用程序框架」(android架構中的第二層)&不是應用程序開發。Android「應用程序框架」Docs/Tuts

我對...感興趣:任何應用程序調用系統/框架API後會發生什麼?操作系統如何檢查該應用是否具有該特定權限? 「應用程序框架」中的哪個組件處理這種檢查?哪些java類負責它?

我想玩這些java類&作一些觀察。

P.S .:我假設權限模型是在「應用程序框架」層實現的。糾正我,如果我錯了。

回答

10

就我所知,框架開發的資源是有限的,大部分可用的資源分佈在不同的博客和郵件列表中。要開始我將推薦開源項目網站,source.android.com。它包含有關如何做事情的有限文檔,但至少提供了使用開源項目的設置。然後是與平臺和框架級開發相關的official mailing lists。不同的ROM項目也可能在網站上提供有用的信息,如Cyanogenmod wiki

然後回答關於如何在框架中實施權限的具體問題。沒有處理檢查的具體組件,框架中的每個服務提供者都需要在允許服務調用通過之前執行權限檢查。在這樣的檢查中涉及兩個重要的部分,系統服務器中的包管理器和Binder IPC機制。包管理器是處理應用程序安裝的操作系統組件。這將在安裝時解析AndroidManifest.xml文件,提示用戶獲取權限並維護特定應用程序擁有的權限的註冊表。這是基於這樣的想法,即每個應用程序都使用自己的Linux用戶標識運行。對於每個uid都有一個權限列表。

第二部分是Binder進程間通信機制。 Binder是面向對象的IPC執行方式,但它也實現了一些安全功能。與權限相關的最重要的一點是它可以使IPC調用的接收端檢查調用者的uid。一個受權限保護的服務將有一個Binder接口,並且會爲接收到的每個請求執行兩件事。首先它會調用綁定器來獲取調用者的uid,然後它會調用提供uid的系統服務器並檢查它是否被授予。如果檢查無誤,它將繼續執行服務調用,否則會引發安全異常。

如果我們看看源代碼,首先簡單地調用振動器服務。 (以下所有代碼版權均屬於Apache 2.0許可下的Android開源項目)。

public void vibrate(long milliseconds, IBinder token) { 
    if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 
      != PackageManager.PERMISSION_GRANTED) { 
     throw new SecurityException("Requires VIBRATE permission"); 
    } 

框架級別權限檢查的實現屬於Context類,更具體地說我們有ContextImpl。java的文件,其中

@Override 
public int checkCallingOrSelfPermission(String permission) { 
    if (permission == null) { 
     throw new IllegalArgumentException("permission is null"); 
    } 

    return checkPermission(permission, Binder.getCallingPid(), 
      Binder.getCallingUid()); 
} 
@Override 
public int checkPermission(String permission, int pid, int uid) { 
    if (permission == null) { 
     throw new IllegalArgumentException("permission is null"); 
    } 

    try { 
     return ActivityManagerNative.getDefault().checkPermission(
       permission, pid, uid); 
    } catch (RemoteException e) { 
     return PackageManager.PERMISSION_DENIED; 
    } 
} 

這是通過活頁夾調用ActivityManagerService,我們將在最後:

/** 
* As the only public entry point for permissions checking, this method 
* can enforce the semantic that requesting a check on a null global 
* permission is automatically denied. (Internally a null permission 
* string is used when calling {@link #checkComponentPermission} in cases 
* when only uid-based security is needed.) 
* 
* This can be called with or without the global lock held. 
*/ 
public int checkPermission(String permission, int pid, int uid) { 
    if (permission == null) { 
     return PackageManager.PERMISSION_DENIED; 
    } 
    return checkComponentPermission(permission, pid, uid, -1, true); 
} 
/** 
* This can be called with or without the global lock held. 
*/ 
int checkComponentPermission(String permission, int pid, int uid, 
     int owningUid, boolean exported) { 
    // We might be performing an operation on behalf of an indirect binder 
    // invocation, e.g. via {@link #openContentUri}. Check and adjust the 
    // client identity accordingly before proceeding. 
    Identity tlsIdentity = sCallerIdentity.get(); 
    if (tlsIdentity != null) { 
     Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {" 
       + tlsIdentity.pid + "," + tlsIdentity.uid + "}"); 
     uid = tlsIdentity.uid; 
     pid = tlsIdentity.pid; 
    } 

    // Root, system server and our own process get to do everything. 
    if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) { 
     return PackageManager.PERMISSION_GRANTED; 
    } 
    // If there is a uid that owns whatever is being accessed, it has 
    // blanket access to it regardless of the permissions it requires. 
    if (owningUid >= 0 && uid == owningUid) { 
     return PackageManager.PERMISSION_GRANTED; 
    } 
    // If the target is not exported, then nobody else can get to it. 
    if (!exported) { 
     Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid); 
     return PackageManager.PERMISSION_DENIED; 
    } 
    if (permission == null) { 
     return PackageManager.PERMISSION_GRANTED; 
    } 
    try { 
     return AppGlobals.getPackageManager() 
       .checkUidPermission(permission, uid); 
    } catch (RemoteException e) { 
     // Should never happen, but if it does... deny! 
     Slog.e(TAG, "PackageManager is dead?!?", e); 
    } 
    return PackageManager.PERMISSION_DENIED; 
} 

的包管理的呼叫checkUidPermission是什麼將執行查找匹配的UID與授予權限的表。如果你想繼續追蹤源代碼,那麼相關的文件就是PackageManagerService.java。

如果您只是在做一項研究,請隨意直接參考開源項目中frameworks/base /中的代碼。上面提到的所有文件都在那裏。按照構建說明進行操作,您應該能夠使用模擬器測試您的更改。如果你不想修改核心框架文件,可以看看/ device/sample中關於如何進行框架擴展的示例。也就是說,大多數與權限相關的API都可以從應用程序級別獲得,因此只需提供一個提供服務的應用程序並對其進行自己的權限檢查即可成功。

+0

哇!這裏給出的很好的解釋!謝謝。 順便說一句,你怎麼知道這麼多東西(通過學習源文件)?我非常有興趣瞭解這一切。 – user1010

+0

自從源代碼發佈以來,我一直在Android平臺級別工作,超過3年。我想我的知識來自不同郵件列表,博客和視頻的信息,以及花費無數小時學習源代碼文件。 – BMB

+0

:)再次感謝你。 – user1010