2012-01-24 30 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