最近遇上一個問題--客戶想要給他們的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