"设备管理应用"界面列表中应用的激活状态是通过DevicePolicyManager的isAdminActiveAsUser()方法获取的
设置中,"设备管理应用"界面应用列表数据加载逻辑如下:
> 通过DeviceAdminSettings.java的addActiveAdminsForProfile()和addDeviceAdminBroadcastReceiversForProfile()方法获取应用列表:
packages/apps/Settings/src/com/android/settings/DeviceAdminSettings.java
private void updateAvailableAdminsForProfile(final int profileId) {
// We are adding the union of two sets 'A' and 'B' of device admins to mAvailableAdmins.
// Set 'A' is the set of active admins for the profile whereas set 'B' is the set of
// listeners to DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED for the profile.
// Add all of set 'A' to mAvailableAdmins.
List<ComponentName> activeAdminsListForProfile = mDPM.getActiveAdminsAsUser(profileId);
addActiveAdminsForProfile(activeAdminsListForProfile, profileId);
// Collect set 'B' and add B-A to mAvailableAdmins.
addDeviceAdminBroadcastReceiversForProfile(activeAdminsListForProfile, profileId);
}
>获取显示的应用列表.
private void addActiveAdminsForProfile(final List<ComponentName> activeAdmins,
final int profileId) {
if (activeAdmins != null) {
final PackageManager packageManager = getActivity().getPackageManager();
final IPackageManager iPackageManager = AppGlobals.getPackageManager();
final int n = activeAdmins.size();
for (int i = 0; i < n; ++i) {
final ComponentName activeAdmin = activeAdmins.get(i);
final ActivityInfo ai;
try {
ai = iPackageManager.getReceiverInfo(activeAdmin,
PackageManager.GET_META_DATA |
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
PackageManager.MATCH_DIRECT_BOOT_UNAWARE |
PackageManager.MATCH_DIRECT_BOOT_AWARE, profileId);
} catch (RemoteException e) {
Log.w(TAG, "Unable to load component: " + activeAdmin);
continue;
}
final DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo(ai);
if (deviceAdminInfo == null) {
continue;
}
// Don't do the applicationInfo.isInternal() check here; if an active
// admin is already on SD card, just show it.
final DeviceAdminListItem item = new DeviceAdminListItem();
item.info = deviceAdminInfo;
item.name = deviceAdminInfo.loadLabel(packageManager).toString();
item.active = true;
mAdmins.add(item);
}
}
}
private void addDeviceAdminBroadcastReceiversForProfile(
Collection<ComponentName> alreadyAddedComponents, final int profileId) {
final PackageManager pm = getActivity().getPackageManager();
List<ResolveInfo> enabledForProfile = pm.queryBroadcastReceiversAsUser(
new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
profileId);
if (enabledForProfile == null) {
enabledForProfile = Collections.emptyList();
}
final int n = enabledForProfile.size();
for (int i = 0; i < n; ++i) {
ResolveInfo resolveInfo = enabledForProfile.get(i);
ComponentName riComponentName =
new ComponentName(resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name);
if (alreadyAddedComponents == null
|| !alreadyAddedComponents.contains(riComponentName)) {
DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo(resolveInfo.activityInfo);
// add only visible ones (note: active admins are added regardless of visibility)
if (deviceAdminInfo != null && deviceAdminInfo.isVisible()) {
if (!deviceAdminInfo.getActivityInfo().applicationInfo.isInternal()) {
continue;
}
DeviceAdminListItem item = new DeviceAdminListItem();
item.info = deviceAdminInfo;
item.name = deviceAdminInfo.loadLabel(pm).toString();
// Active ones already added.
item.active = false;
mAdmins.add(item);
}
}
}
}
> 通过DeviceAdminSettings.java的isActiveAdmin()方法获取应用激活状态:
private boolean isActiveAdmin(DeviceAdminInfo item) {
return mDPM.isAdminActiveAsUser(item.getComponent(), getUserId(item));
}
> 设置中调用mDPM.getActiveAdminsAsUser(profileId)来确定列表的数目,该接口是DevicePolicyManager通过Binder调用DeviceManagerService.java中的接口
进入frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
public @Nullable List<ComponentName> getActiveAdminsAsUser(int userId) {
1609 if (mService != null) {
1610 try {
1611 return mService.getActiveAdmins(userId);
1612 } catch (RemoteException e) {
1613 throw e.rethrowFromSystemServer();
1614 }
> 跟踪mService.getActiveAdmins(userId)进入frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@SuppressWarnings("unchecked")
3280 public List<ComponentName> getActiveAdmins(int userHandle) {
3281 if (!mHasFeature) {
3282 return Collections.EMPTY_LIST;
3283 }
3284
3285 enforceFullCrossUsersPermission(userHandle);
3286 synchronized (this) {
3287 DevicePolicyData policy = getUserData(userHandle);
3288 final int N = policy.mAdminList.size();
3289 if (N <= 0) {
3290 return null;
3291 }
3292 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
3293 for (int i=0; i<N; i++) {
3294 res.add(policy.mAdminList.get(i).info.getComponent());
3295 }
3296 return res;
3297 }
3298 }
>从本地的List里面复制了一份给返回,在这个文件里就找到了两处add:一处在 setActiveAdmin,一致在 loadSettingsLocked ,setActiveAdmin发现他是一个hide的借口存在于Manager类上,第三发的应用是不能调到的,在loadSettingsLocked。在这个函数里面在做xml的parser.代码比较长,不全列出来
private void saveSettingsLocked(int userHandle) {
2511 DevicePolicyData policy = getUserData(userHandle);
2512 JournaledFile journal = makeJournaledFile(userHandle);
2513 FileOutputStream stream = null;
2514 try {
2515 stream = new FileOutputStream(journal.chooseForWrite(), false);
2516 XmlSerializer out = new FastXmlSerializer();
2517 out.setOutput(stream, StandardCharsets.UTF_8.name());
2518 out.startDocument(null, true);
2519
2520 out.startTag(null, "policies");
2521 if (policy.mRestrictionsProvider != null) {
2522 out.attribute(null, ATTR_PERMISSION_PROVIDER,
2523 policy.mRestrictionsProvider.flattenToString());
>从上面代码可以看出,JournaledFile journal = makeJournaledFile(userHandle)加载需要解析的xml文件,进入该函数发现需要解析的xml文件为device_policies.xml
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
private JournaledFile makeJournaledFile(int userHandle) {
2500 final String base = userHandle == UserHandle.USER_SYSTEM
2501 ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
2502 : new File(mInjector.environmentGetUserSystemDirectory(userHandle),
2503 DEVICE_POLICIES_XML).getAbsolutePath();
2504 if (VERBOSE_LOG) {
2505 Log.v(LOG_TAG, "Opening " + base);
2506 }
2507 return new JournaledFile(new File(base), new File(base + ".tmp"));
2508 }
>综上,显示列表是DeviceManagerService.java来解析device_policies.xml文件,并非通过配置文件或者增加功能来显示的.
>列表选项是否默认,Settings中通过DeviceAdminSettings.java的isActiveAdmin()方法获取应用激活状态:
private boolean isActiveAdmin(DeviceAdminInfo item) {
return mDPM.isAdminActiveAsUser(item.getComponent(), getUserId(item));
}
> 跟踪mDPM.isAdminActiveAsUser(item.getComponent(), getUserId(item));进入frameworks/base/core/java/android/app/admin/DevicePolicyManager.java
567 public boolean isAdminActiveAsUser(@NonNull ComponentName admin, int userId) {
1568 if (mService != null) {
1569 try {
1570 return mService.isAdminActive(admin, userId);
1571 } catch (RemoteException e) {
1572 throw e.rethrowFromSystemServer();
1573 }
1574 }
1575 return false;
1576 }
>同理,通过Binder机制,进入DeviceMangerService.java文件中发现调用的是getActiveAdminUncheckedLocked(adminReceiver, userHandle)接口,进一步跟踪进入.
3241 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
3242 if (!mHasFeature) {
3243 return false;
3244 }
3245 enforceFullCrossUsersPermission(userHandle);
3246 synchronized (this) {
3247 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
3248 }
3249 }
> 查看传入的参数在mAdminMap中是否存在.
9 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
2250 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
2251 if (admin != null
2252 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
2253 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
2254 return admin;
2255 }
2256 return null;
2257 }
> 我们来查看谁向mAdminMap中写入参数.查看在 loadSettingsLocked接口中有mAdminMap.put操作,由如下代码来看,是通过解析device_policy.xml来决定是否默认选中的.
private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
2708 JournaledFile journal = makeJournaledFile(userHandle);
2709 FileInputStream stream = null;
2710 File file = journal.chooseForRead();
2711 boolean needsRewrite = false;
2712 try {
2713 stream = new FileInputStream(file);
2714 XmlPullParser parser = Xml.newPullParser();
2715 parser.setInput(stream, StandardCharsets.UTF_8.name());
2716
...
...
+ userHandle);
2810 }
2811 if (dai != null) {
2812 ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false);
2813 ap.readFromXml(parser);
2814 policy.mAdminMap.put(ap.info.getComponent(), ap);
2815 }
2816 } catch (RuntimeException e) {
2817 Slog.w(LOG_TAG, "Failed loading admin " + name, e);
2818 }
> 综上所述,该界面显示的列表已经相应列表是否默认选中,都是通过解析device_policy.xml文件来决定的,并非是某个配置文件通过简单修改即可.
该机制为Android 原生机制,强制修改存在不可控风险