用到的代码文件
frameworks/base/core/java/:
android/content/ContextWrapper.java
android/content/Intent.java
android/app/ContextImpl.java
frameworks/base/services/core/java/:
com/android/server/am/ActivityManagerService.java
com/android/server/am/UriPermission.java
代码执行流程图
grantUriPermission()方法执行流程
下面的代码基于android O(api 27)。
本文基于MTK(MediaTek)平台基线。
本文主要是记录在Activity中调用grantUriPermission()方法的执行流程。
因为Activity继承自ContextWrapper,所以其实质为调用ContextWrapper中的grantUriPermission()方法。
下面进入ContextWrapper类中的grantUriPermission()方法。
@Override
public void grantUriPermission(String toPackage,
Uri uri, int modeFlags) {
/*
这里是我调用这个方法时传递的参数
pkg: com.android.bluetooth
uri: content://com.***.filemanager.fileProvider/
external_storage/mtklog/file_tree.txt
flags: 1 -> Intent.FLAG_GRANT_READ_URI_PERMISSION
*/
log("method grantUriPermission() pkg: " + toPackage
+ " uri: " + uri + " flags: " + modeFlags);
/*
mBase: android.app.ContextImpl
*/
log("mBase: " + mBase.getClass().getName());
mBase.grantUriPermission(toPackage, uri, modeFlags);
}
下面进入ContextImpl类中的grantUriPermission()方法。
@Override
public void grantUriPermission(String toPackage,
Uri uri, int modeFlags) {
try {
// 0
log("resolveUserId(uri): " + resolveUserId(uri));
// content://com.***.filemanager.fileProvider/
// external_storage/RobustTest/robust_log.txt
log("ContentProvider.getUriWithoutUserId(uri): "
+ ContentProvider.getUriWithoutUserId(uri).toString());
// android.app.IActivityManager$Stub$Proxy
log("ActivityManager.getService(): "
+ ActivityManager.getService().getClass().getName());
/*
* 这里的实质就是跨进程通信了,ActivityManagerService (AMS)
*/
ActivityManager.getService().grantUriPermission(
mMainThread.getApplicationThread(), toPackage,
ContentProvider.getUriWithoutUserId(uri),
modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
下面进入ActivityManagerService类中的grantUriPermission()方法。
/**
* @param uri This uri must NOT contain an embedded userId.
* @param userId The userId in which the uri is to be resolved.
*/
@Override
public void grantUriPermission(IApplicationThread caller,
String targetPkg, Uri uri,final int modeFlags,
int userId) {
log("method grantUriPermission()");
/*
caller: android.app.IApplicationThread$Stub$Proxy
targetPkg: com.android.bluetooth
uri: content://com.***.filemanager.fileProvider/
external_storage/RobustTest/robust_log.txt
modeFlags: 1
userId: 0
*/
log("caller: " + caller.getClass().getName());
log("targetPkg: " + targetPkg);
log("uri: " + uri);
log("modeFlags: " + modeFlags);
log("userId: " + userId);
/*
* 确保当前不是被孤立的进程来调用这个方法
* 这个方法的实质就是通过uid来获取对应的app id并判断其是否合法
*/
enforceNotIsolatedCaller("grantUriPermission");
/*
* GrantUri是定义在ActivityManagerService中的静态内部类
*/
GrantUri grantUri = new GrantUri(userId, uri, false);
/*
* 确保uri permission相关逻辑线程安全
* 因为这个操作任何应用都可以调用
*/
synchronized(this) {
//获取调用进程的ProcessRecord对象
final ProcessRecord r = getRecordForAppLocked(caller);
//ProcessRecord{4b47804 1458:com.android.bluetooth/1002}
log("r: "+r);
if (r == null) {
throw new SecurityException("Unable to find app for caller "
+ caller
+ " when granting permission to uri " + grantUri);
}
if (targetPkg == null) {
throw new IllegalArgumentException("null target");
}
if (grantUri == null) {
throw new IllegalArgumentException("null uri");
}
/*
检查权限标志位是否合法
给uri设置的权限标志必须是这四种,不然抛出异常
*/
Preconditions.checkFlagsArgument(modeFlags,
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
grantUriPermissionLocked(r.uid, targetPkg, grantUri,
modeFlags, null,
UserHandle.getUserId(r.uid));
}
}
下面进入ActivityManagerService类中的grantUriPermissionLocked()方法。
void grantUriPermissionLocked(int callingUid, String targetPkg,
GrantUri grantUri,final int modeFlags,
UriPermissionOwner owner, int targetUserId) {
log("method grantUriPermissionLocked()");
/*
callingUid: 1002
targetPkg: com.android.bluetooth
grantUri: content://com.***.filemanager.fileProvider/
external_storage/RobustTest/robust_log.txt [user 0]
modeFlags: 1
owner: null
targetUserId: 0
*/
log("callingUid: " + callingUid);
log("targetPkg: " + targetPkg);
log("grantUri: " + grantUri);
log("modeFlags: " + modeFlags);
log("owner: " + owner);
log("targetUserId: " + targetUserId);
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
int targetUid;
final IPackageManager pm = AppGlobals.getPackageManager();
//pm: com.android.server.pm.PackageManagerService
log("pm: " + pm.getClass().getName());
try {
//使用PMS来查询当前包名对应的uid
targetUid = pm.getPackageUid(targetPkg,
MATCH_DEBUG_TRIAGED_MISSING, targetUserId);
} catch (RemoteException ex) {
return;
}
log("targetUid1: " + targetUid);
/*
* 这个方法主要是检查当前uri要设置的权限是否已经被设置过了
* 如果当前uri不允许设置这种权限那么就会抛出异常
*/
targetUid = checkGrantUriPermissionLocked(callingUid,
targetPkg, grantUri, modeFlags,targetUid);
log("targetUid2: " + targetUid);
if (targetUid < 0) {
return;
}
grantUriPermissionUncheckedLocked(targetUid, targetPkg,
grantUri, modeFlags,owner);
}
下面进入ActivityManagerService类中的grantUriPermissionUncheckedLocked()方法。
void grantUriPermissionUncheckedLocked(int targetUid,
String targetPkg, GrantUri grantUri,
final int modeFlags, UriPermissionOwner owner) {
log("method grantUriPermissionUncheckedLocked()");
/*
* 判断当前uri要设置的uri是否被允许使用
* 检查read or write权限
*/
if (!Intent.isAccessUriMode(modeFlags)) {
return;
}
// So here we are: the caller has the assumed permission
// to the uri, and the target doesn't. Let's now give this
// to the target.
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Granting " + targetPkg + "/" + targetUid
+ " permission to " + grantUri);
final String authority = grantUri.uri.getAuthority();
//com.***.filemanager.fileProvider
log("authority: " + authority);
//获取uri对应的provider信息
final ProviderInfo pi = getProviderInfoLocked(authority,
grantUri.sourceUserId,MATCH_DEBUG_TRIAGED_MISSING);
//ContentProviderInfo{name=com.***.filemanager.fileProvider
//className=android.support.v4.content.FileProvider}
log("pi: " + pi);
if (pi == null) {
Slog.w(TAG, "No content provider found for grant: "
+ grantUri.toSafeString());
return;
}
// -> false
if ((modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) {
log("set grant uri prefix true");
grantUri.prefix = true;
}
/*
* 进入这里
*/
final UriPermission perm = findOrCreateUriPermissionLocked(
pi.packageName, targetPkg, targetUid, grantUri);
log("perm: " + perm);
log("perm: " + perm.getClass().getName());
/*
* 再进入这里
*/
perm.grantModes(modeFlags, owner);
}
下面进入ActivityManagerService类中的findOrCreateUriPermissionLocked()方法。
/**
* Global set of specific {@link Uri} permissions that have
* been granted.
* This optimized lookup structure maps from
* {@link UriPermission#targetUid}
* to {@link UriPermission#uri} to {@link UriPermission}.
*
* 看这个注释就应该明白了。
* 每个uri被封装为一个GrantUri对象,
* 而每一个GrantUri对象对应一个UriPermission对象
*/
@GuardedBy("this")
private final SparseArray<ArrayMap<GrantUri, UriPermission>>
mGrantedUriPermissions =
new SparseArray<ArrayMap<GrantUri, UriPermission>>();
private UriPermission findOrCreateUriPermissionLocked(
String sourcePkg,String targetPkg, int targetUid,
GrantUri grantUri) {
ArrayMap<GrantUri, UriPermission> targetUris =
mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
targetUris = Maps.newArrayMap();
mGrantedUriPermissions.put(targetUid, targetUris);
}
UriPermission perm = targetUris.get(grantUri);
if (perm == null) {
perm = new UriPermission(sourcePkg, targetPkg,
targetUid, grantUri);
targetUris.put(grantUri, perm);
}
return perm;
}
下面进入UriPermission类中的findOrCreateUriPermissionLocked()方法。
void grantModes(int modeFlags, UriPermissionOwner owner) {
// modeFlags: 1 owner: null
log("method grantModes() modeFlags: "+modeFlags+" owner: "+owner);
final boolean persistable = (modeFlags &
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
//persistable: false
log("persistable: "+persistable);
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
//modeFlags: 1
log("modeFlags: "+modeFlags);
if (persistable) {
persistableModeFlags |= modeFlags;
}
if (owner == null) {// -> true
globalModeFlags |= modeFlags;
} else {
if ((modeFlags
& Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
addReadOwner(owner);
}
if ((modeFlags
& Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
addWriteOwner(owner);
}
}
updateModeFlags();
}
下面进入UriPermission类中的updateModeFlags()方法。
private void updateModeFlags() {
final int oldModeFlags = modeFlags;
/*
*更新下modeFlags的标志位就完了
*/
modeFlags = ownedModeFlags | globalModeFlags
| persistableModeFlags | persistedModeFlags;
if (Log.isLoggable(TAG, Log.VERBOSE)
&& (modeFlags != oldModeFlags)) {
Slog.d(TAG,
"Permission for " + targetPkg + " to " + uri
+ " is changing from 0x"
+ Integer.toHexString(oldModeFlags) + " to 0x"
+ Integer.toHexString(modeFlags)
+ " via calling UID "
+ Binder.getCallingUid() + " PID "
+ Binder.getCallingPid(),
new Throwable());
}
}
至此在Activity中调用grantUriPermission()方法的执行流程就执行完了。
执行流程总结
每个uri被封装为一个GrantUri对象,而每一个GrantUri对象对应一个UriPermission对象。
最终存储在ActivityManagerService中的mGrantedUriPermissions这个SparseArray对象中。
谁会检查?
1.ContentProvider.java中的enforceReadPermissionInner()方法。
2.ActivityManagerService.java中的checkContentProviderPermissionLocked()方法。
3.以后遇见了再补充......
后记
写这篇文章的原因是最近项目上遇见了一个Uri权限的问题,使用grantUriPermission()这个方法就能通过权限的检查。当时使用了就使用了并没有去深究其中的原因,但是不知道为什么不是我做事的态度,所以今天查看了源码,探究了其中的原因。
“知其然知其所以然”!
本文由 tuzhao 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
2018/01/17 23:31