Насколько мне известно, ресурсы для разработки фреймворка ограничены, большая часть того, что доступно, разбросана по разным блогам и спискам рассылки. Для начала я бы порекомендовал сайт проекта с открытым исходным кодом source.android.com. Он содержит ограниченную документацию о том, как что-то делать, но, по крайней мере, обеспечивает настройку для работы с проектом с открытым исходным кодом. Кроме того, есть официальные списки рассылки, связанные с разработкой на уровне платформы и фреймворка. Различные ROM-проекты также могут содержать полезную информацию на таких сайтах, как вики Cyanogenmod.
Затем, чтобы ответить на ваш конкретный вопрос о том, как разрешения реализованы в рамках. Нет специального компонента, который обрабатывает проверки, каждый поставщик услуг в структуре должен выполнить проверку разрешений, прежде чем разрешать вызов службы. В такой проверке участвуют две важные части: менеджер пакетов на системном сервере и механизм IPC Binder. Диспетчер пакетов — это компонент ОС, отвечающий за установку приложений. Это проанализирует файл AndroidManifest.xml при установке, запросит у пользователя разрешения и сохранит реестр разрешений, которыми обладает конкретное приложение. Это основано на идее, что каждое приложение работает со своим собственным идентификатором пользователя Linux. Для каждого uid есть список разрешений.
Вторая часть — это механизм межпроцессного взаимодействия Binder. Binder — это объектно-ориентированный способ выполнения IPC, но он также реализует некоторые функции безопасности. Самый важный из них, связанный с разрешениями, заключается в том, что он позволяет принимающей стороне вызова IPC проверять uid вызывающего абонента. Служба, защищенная разрешением, будет иметь интерфейс Binder и будет делать две вещи для каждого полученного запроса. Сначала он вызовет связыватель, чтобы получить uid вызывающего абонента, а затем вызовет системный сервер, предоставив uid и разрешение, чтобы проверить, было ли оно предоставлено. Если проверка прошла успешно, она будет продолжена и выполнит вызов службы, в противном случае возникнет исключение безопасности.
Если мы посмотрим на исходный код, начиная с простого вызова службы вибратора. (Все приведенные ниже коды защищены авторскими правами проекта Android с открытым исходным кодом в соответствии с лицензией 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-интерфейсов, связанных с разрешениями, доступны на уровне приложения, поэтому вы можете добиться успеха, просто имея приложение, которое предоставляет услугу, и выполняйте собственную проверку разрешений на это.
person
BMB
schedule
25.01.2012