Android"应用程序框架"Docs/Tuts

use*_*010 4 android android-source android-framework

有人能指出我与Android应用程序框架开发相关的教程吗?在这里,我特别谈论"应用程序框架"(Android架构顶部的第二层)而不是App开发.

我感兴趣的是:在任何应用程序调用系统/框架API后会发生什么?操作系统如何检查该应用程序是否具有该特定权限?"应用程序框架"中的哪个组件处理此检查?哪个java类负责呢?

我想玩这些java类并做一些观察.

PS:我假设权限模型是在"应用程序框架"层中实现的.如果我错了,请纠正我.

BMB*_*BMB 10

据我所知,框架开发的资源有限,大部分可用资源分布在不同的博客和邮件列表中.要开始,我会推荐开源项目站点source.android.com.它包含有关如何执行操作的有限文档,但至少提供了使用开源项目的设置.然后是与平台和框架级开发相关的官方邮件列表.不同的ROM项目也可能在Cyanogenmod wiki等网站上提供有用的信息.

然后回答有关如何在框架中实现权限的特定问题.没有处理检查的特定组件,框架中的每个服务提供者都需要在允许服务调用之前执行权限检查.这种检查涉及两个重要部分,系统服务器中的包管理器和Binder IPC机制.包管理器是处理应用程序安装的OS组件.这将在安装时解析AndroidManifest.xml文件,提示用户输入权限并维护特定应用程序拥有的权限的注册表.这是基于每个应用程序使用自己的Linux用户ID运行的想法.对于每个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");
    }
Run Code Online (Sandbox Code Playgroud)

框架级别权限检查的实现属于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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是通过Binder调用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;
}
Run Code Online (Sandbox Code Playgroud)

对包管理器checkUidPermission的调用将执行查找以使uid与已授予权限的表匹配.如果要继续跟踪源,则相关文件为PackageManagerService.java.

如果您正在进行研究,请随意深入研究开源项目中框架/ base /中的代码.上面提到的所有文件都在那里.按照构建说明操作,您应该能够使用模拟器测试更改.如果您不想自己修改核心框架文件,请查看/ device/sample中有关如何进行框架扩展的示例.也就是说,大多数与权限相关的API都可以从应用程序级别获得,因此您可以成功地拥有一个提供服务的应用程序并自行检查该权限.