最近遇上一个问题--客户想要给他们的apk默认加上运行时权限,分享一下我的解决方法。
Google其实在系统第一次开机的时候是会打开一些Apk的运行时权限的,加入的地方在alps/frameworks/base/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java,里面会有一系列的APK的默认运行时权限的赋予,比如GoogleGo(也就是Search),Email,Browser一类的,比如像Browser:
// Browser
PackageParser.Package browserPackage = null;
String defaultBrowserPackage = mService.getDefaultBrowserPackageName(userId);
if (defaultBrowserPackage != null) {
browserPackage = getPackageLPr(defaultBrowserPackage);
}
if (browserPackage == null) {
Intent browserIntent = new Intent(Intent.ACTION_MAIN);
browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
browserPackage = getDefaultSystemHandlerActivityPackageLPr(
browserIntent, userId);
}
if (browserPackage != null
&& doesPackageSupportRuntimePermissions(browserPackage)) {
grantRuntimePermissionsLPw(browserPackage, LOCATION_PERMISSIONS, userId);
}
所以我们也可以在这个地方加入我们所需的权限,比如说我要加一个给CSDN的apk加入获取位置权限的话(我并不知道这个apk的包名,就举例是com.example.csdn):
PackageParser.Package mCSDNPackage = null;
mCSDNPackage= getSystemPackageLPr("com.example.csdn");
if (mCSDNPackage != null && doesPackageSupportRuntimePermissions(mCSDNPackage)) {
grantRuntimePermissionsLPw(mCSDNPackage, LOCATION_PERMISSIONS, userId);
}
在这个类中有一些常量对应着各个权限:
private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
static {
PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
PHONE_PERMISSIONS.add(Manifest.permission.READ_CALL_LOG);
PHONE_PERMISSIONS.add(Manifest.permission.WRITE_CALL_LOG);
PHONE_PERMISSIONS.add(Manifest.permission.ADD_VOICEMAIL);
PHONE_PERMISSIONS.add(Manifest.permission.USE_SIP);
PHONE_PERMISSIONS.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
}
private static final Set<String> CONTACTS_PERMISSIONS = new ArraySet<>();
static {
CONTACTS_PERMISSIONS.add(Manifest.permission.READ_CONTACTS);
CONTACTS_PERMISSIONS.add(Manifest.permission.WRITE_CONTACTS);
CONTACTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
}
private static final Set<String> LOCATION_PERMISSIONS = new ArraySet<>();
static {
LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
private static final Set<String> CALENDAR_PERMISSIONS = new ArraySet<>();
static {
CALENDAR_PERMISSIONS.add(Manifest.permission.READ_CALENDAR);
CALENDAR_PERMISSIONS.add(Manifest.permission.WRITE_CALENDAR);
}
private static final Set<String> SMS_PERMISSIONS = new ArraySet<>();
static {
SMS_PERMISSIONS.add(Manifest.permission.SEND_SMS);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_SMS);
SMS_PERMISSIONS.add(Manifest.permission.READ_SMS);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_WAP_PUSH);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_MMS);
SMS_PERMISSIONS.add(Manifest.permission.READ_CELL_BROADCASTS);
}
private static final Set<String> MICROPHONE_PERMISSIONS = new ArraySet<>();
static {
MICROPHONE_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
}
private static final Set<String> CAMERA_PERMISSIONS = new ArraySet<>();
static {
CAMERA_PERMISSIONS.add(Manifest.permission.CAMERA);
}
private static final Set<String> SENSORS_PERMISSIONS = new ArraySet<>();
static {
SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
}
private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
static {
STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
我们可以根据这些加入需求的权限,这样的话在重新刷机我们就会发现我们需要的运行是权限已经变为了开启。
但是!!!这个方法是过不了GTS的。国内是没关系,但是给国外的话很多时候是要预置GMS包的,是要过GTS的,com.google.android.permission.gts.DefaultPermissionGrantPolicyTest#testDefaultGrantsWithRemoteExceptions这一项是过不了的。那怎么办呢?经过我的重重努力,终于找到一个方法解决这个问题。
其实在GTS测试的时候CTS工具也是调用的系统的测试接口,我们可以在alps/frameworks/base/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java 这个类中找到一个checkPermission(String permName, String pkgName)的方法:
@Override
public int checkPermission(String permName, String pkgName) {
try {
return mPM.checkPermission(permName, pkgName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这个便是GTS测试的时候调用的系统方法,当然平常s我们可以将他这样改:
@Override
public int checkPermission(String permName, String pkgName) {
try {
String taker = mContext.getPackageName();
if ("com.google.android.permission.gts".equals(taker)) {
String[] whiteLists = new String[] {"com.example.csdn"};
for (String pkg : whiteLists) {
if (pkg.equals(pkgName)) {
return PERMISSION_DENIED;
}
}
}
return mPM.checkPermission(permName, pkgName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
判断是否是GTS测试在调用,是的话就返回PERMISSION_DENIED;不是的还是返回原来代码中的。这样的话你就会发现能够将com.google.android.permission.gts.DefaultPermissionGrantPolicyTest#testDefaultGrantsWithRemoteExceptions这一项给测过了。
最后要着重说明一件事情,现在google对这些以判断形式过GMS的查的很严,出事了问题还是很严重的,所以如果客户不是特别特别要求一定要这样做或者他们愿意承担责任,不然还是不建议这样去过GMS,授权需谨慎,强烈不建议这么做,出现问题与本人无关。
https://source.android.com/devices/tech/config/perms-whitelist