Насколько мне известно, ресурсы для разработки фреймворка ограничены, большая часть того, что доступно, размещена в разных блогах и списках рассылки. Для начала я бы порекомендовал сайт проекта с открытым исходным кодом, source.android.com . Он содержит ограниченную документацию о том, как что-то делать, но, по крайней мере, предоставляет настройки для работы с проектом с открытым исходным кодом. Затем есть официальные списки рассылки , связанные с разработкой на уровне платформы и фреймворка. Различные ROM-проекты могут также содержать полезную информацию на таких сайтах, как Cyanogenmod wiki .
Тогда, чтобы ответить на ваш конкретный вопрос о том, как разрешения реализованы в фреймворке. Нет конкретного компонента, который обрабатывает проверки, каждый поставщик услуг в структуре должен выполнить проверку разрешений, прежде чем разрешить вызов службы. В такой проверке участвуют две важные части: менеджер пакетов на системном сервере и механизм Binder IPC. Менеджер пакетов - это компонент ОС, который управляет установкой приложений. Это позволит проанализировать файл AndroidManifest.xml при установке, запросить у пользователя разрешения и вести реестр того, какие разрешения содержит конкретное приложение. Это основано на идее, что каждое приложение работает со своим собственным идентификатором пользователя Linux. Для каждого идентификатора есть список разрешений.
Вторая часть - это механизм межпроцессного взаимодействия Binder. Binder - это объектно-ориентированный способ выполнения IPC, но он также реализует некоторые функции безопасности. Наиболее важным, связанным с разрешениями, является то, что для принимающей стороны вызова IPC можно проверить идентификатор вызывающей стороны. Служба, защищенная разрешением, будет иметь интерфейс Binder и будет выполнять две функции для каждого полученного запроса. Сначала он вызывает связыватель для получения идентификатора вызывающей стороны, а затем вызывает системный сервер, предоставляющий идентификатор и разрешение, чтобы проверить, было ли оно предоставлено. Если проверка в порядке, она продолжится и выполнит служебный вызов, в противном случае возникнет исключение безопасности.
Если мы посмотрим на исходный код, начнем с простого звонка в службу вибратора. (Весь приведенный ниже код защищен авторским правом Android Open Source Project под лицензией Apache 2.0).
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;
}
}
Это вызов через 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;
}
Вызов менеджера пакетов checkUidPermission - это то, что выполнит поиск, чтобы сопоставить uid с таблицами предоставленных разрешений. Если вы хотите продолжить трассировку источника, соответствующий файл - PackageManagerService.java.
Если вы только делаете исследование, не стесняйтесь погружаться прямо в код в frameworks / base / в проекте с открытым исходным кодом. Все упомянутые выше файлы находятся там. Следуйте инструкциям по сборке, и вы сможете проверить свои изменения с помощью эмулятора. Если вы не хотите изменять файлы ядра фреймворка, посмотрите на пример в / device / sample о том, как сделать расширения фреймворка. Тем не менее, большинство API-интерфейсов, связанных с разрешениями, доступны на уровне приложений, поэтому вы можете добиться успеха, просто имея приложение, предоставляющее услугу, и выполните свою собственную проверку разрешений.