项目中系统自带Dialer应用不是默认应用,导致输入暗码不能启动工程模式。
1.加载默认支持的role
RoleManagert和RoleManagerService主要用来管理默认应用设置的,RoleManagerService继承SystemService,在启动的时候开始加载系统默认支持的role。
- frameworks/base/services/core/java/com/android/server/role/RoleManagerService.java
@Override
public void onStart() {
publishBinderService(Context.ROLE_SERVICE, new Stub());
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
getContext().registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int userId = UserHandle.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
if (DEBUG) {
Slog.i(LOG_TAG, "Packages changed - re-running initial grants for user "
+ userId);
}
if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED
return;
}
maybeGrantDefaultRolesAsync(userId);
}
}, UserHandle.ALL, intentFilter, null, null);
}
private void maybeGrantDefaultRolesAsync(@UserIdInt int userId) {
ThrottledRunnable runnable;
synchronized (mLock) {
runnable = mGrantDefaultRolesThrottledRunnables.get(userId);
if (runnable == null) {
runnable = new ThrottledRunnable(FgThread.getHandler(),
GRANT_DEFAULT_ROLES_INTERVAL_MILLIS,
() -> maybeGrantDefaultRolesInternal(userId));
mGrantDefaultRolesThrottledRunnables.put(userId, runnable);
}
}
runnable.run();
}
// 加载默认支持的role
@AnyThread
@NonNull
private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) {
// 根据userId创建RoleUserState,在RoleUserState中解析roles.xml,但是framework下没有roles.xml文件
RoleUserState userState = getOrCreateUserState(userId);
String oldPackagesHash = userState.getPackagesHash();
String newPackagesHash = computeComponentStateHash(userId);
if (Objects.equals(oldPackagesHash, newPackagesHash)) {
if (DEBUG) {
Slog.i(LOG_TAG, "Already granted default roles for packages hash "
+ newPackagesHash);
}
return AndroidFuture.completedFuture(null);
}
//TODO gradually add more role migrations statements here for remaining roles
// Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
// for a given role before adding a migration statement for it here
// roles.xml中还有两种
aybeMigrateRole(RoleManager.ROLE_ASSISTANT, userId);
maybeMigrateRole(RoleManager.ROLE_BROWSER, userId);
maybeMigrateRole(RoleManager.ROLE_DIALER, userId);
maybeMigrateRole(RoleManager.ROLE_SMS, userId);
maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId);
maybeMigrateRole(RoleManager.ROLE_HOME, userId);
// Some package state has changed, so grant default roles again.
Slog.i(LOG_TAG, "Granting default roles...");
AndroidFuture<Void> future = new AndroidFuture<>();
//在RoleControllerManager中授予默认role
getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(),
successful -> {
if (successful) {
userState.setPackagesHash(newPackagesHash);
future.complete(null);
} else {
future.completeExceptionally(new RuntimeException());
}
});
return future;
}
走到RoleControllerManager.grantDefaultRoles中
- frameworks/base/core/java/android/app/role/RoleControllerManager.java
/**
* @see RoleControllerService#onGrantDefaultRoles()
*
* @hide
*/
public void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<Boolean> callback) {
AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
AndroidFuture<Bundle> future = new AndroidFuture<>();
service.grantDefaultRoles(new RemoteCallback(future::complete));
return future;
});
propagateCallback(operation, "grantDefaultRoles", executor, callback);
}
然后再到RoleControllerService.grantDefaultRoles中
- frameworks/base/core/java/android/app/role/RoleControllerService.java
@SystemApi
public abstract class RoleControllerService extends Service {
@Nullable
@Override
public final IBinder onBind(@Nullable Intent intent) {
return new IRoleController.Stub() {
@Override
public void grantDefaultRoles(RemoteCallback callback) {
enforceCallerSystemUid("grantDefaultRoles");
Objects.requireNonNull(callback, "callback cannot be null");
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
RoleControllerService::grantDefaultRoles, RoleControllerService.this,
callback));
}
...
)};
}
private void grantDefaultRoles(@NonNull RemoteCallback callback) {
boolean successful = onGrantDefaultRoles();
callback.sendResult(successful ? Bundle.EMPTY : null);
}
@WorkerThread
public abstract boolean onGrantDefaultRoles();
}
RoleControllerService是一个抽象类,它还有一个子类RoleControllerServiceImpl,然后走到RoleControllerServiceImpl.onGrantDefaultRoles方法
- packages/apps/PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java
@Override
@WorkerThread
public boolean onGrantDefaultRoles() {
if (DEBUG) {
Log.i(LOG_TAG, "Granting default roles, user: " + UserHandle.myUserId());
}
//第一步: 解析roles.xml获取所有可用的roles
// Gather the available roles for current user.
ArrayMap<String, Role> roleMap = Roles.get(this);
List<Role> roles = new ArrayList<>();
List<String> roleNames = new ArrayList<>();
ArraySet<String> addedRoleNames = new ArraySet<>();
int roleMapSize = roleMap.size();
for (int i = 0; i < roleMapSize; i++) {
Role role = roleMap.valueAt(i);
// 第二步:判断role是否可用
if (!role.isAvailable(this)) {
continue;
}
roles.add(role);
String roleName = role.getName();
roleNames.add(roleName);
if (!mRoleManager.isRoleAvailable(roleName)) {
addedRoleNames.add(roleName);
}
}
// TODO: Clean up holders of roles that will be removed.
// 第三步:将所有可用的rols设置到RoleManager
// Set the available role names in RoleManager.
mRoleManager.setRoleNamesFromController(roleNames);
...
}
第一步解析roles.xml
onGrantDefaultRoles调用后马上去读取xml–>Roles.get(this)
- packages/apps/PermissionController/src/com/android/permissioncontroller/role/model/Roles.java
@NonNull
public static ArrayMap<String, Role> get(@NonNull Context context) {
synchronized (sLock) {
if (sRoles == null) {
sRoles = new RoleParser(context).parse();
}
return sRoles;
}
}
在RoleParser.java中进行roles.xml的解析
- packages/apps/PermissionController/src/com/android/permissioncontroller/role/model/RoleParser.java
@NonNull
public ArrayMap<String, Role> parse() {
try (XmlResourceParser parser = mContext.getResources().getXml(R.xml.roles)) {
Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> xml = parseXml(parser);
if (xml == null) {
return new ArrayMap<>();
}
ArrayMap<String, PermissionSet> permissionSets = xml.first;
ArrayMap<String, Role> roles = xml.second;
validateResult(permissionSets, roles);
return roles;
} catch (XmlPullParserException | IOException e) {
throwOrLogMessage("Unable to parse roles.xml", e);
return new ArrayMap<>();
}
}
第二步中判断role是否可用
role.isAvailable(this),如果可用进行第三步
- packages/apps/PermissionController/src/com/android/permissioncontroller/role/model/Role.java
public boolean isAvailable(@NonNull Context context) {
return isAvailableAsUser(Process.myUserHandle(), context);
}
...
public boolean isAvailableAsUser(@NonNull UserHandle user, @NonNull Context context) {
if (mBehavior != null) {
return mBehavior.isAvailableAsUser(this, user, context);
}
return true;
}
RoleBehavior是一个接口类,在RoleBehavior.isVisibleAsUser中默认返回true
第三步添加可用role到RoleManager
从RoleManager.setRoleNamesFromController再到RoleManagerService.setRoleNamesFromController
- frameworks/base/services/core/java/com/android/server/role/RoleManagerService.java
@Override
public void setRoleNamesFromController(@NonNull List<String> roleNames) {
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"setRoleNamesFromController");
Objects.requireNonNull(roleNames, "roleNames cannot be null");
int userId = UserHandle.getCallingUserId();
getOrCreateUserState(userId).setRoleNames(roleNames);
}
又来到RoleUserState.setRoleNames
- frameworks/base/services/core/java/com/android/server/role/RoleUserState.java
/**
* Set the names of all available roles.
*
* @param roleNames the names of all the available roles
*/
public void setRoleNames(@NonNull List<String> roleNames) {
synchronized (mLock) {
boolean changed = false;
for (int i = mRoles.size() - 1; i >= 0; i--) {
String roleName = mRoles.keyAt(i);
if (!roleNames.contains(roleName)) {
ArraySet<String> packageNames = mRoles.valueAt(i);
if (!packageNames.isEmpty()) {
Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up,"
+ " role: " + roleName + ", holders: " + packageNames);
}
mRoles.removeAt(i);
changed = true;
}
}
int roleNamesSize = roleNames.size();
for (int i = 0; i < roleNamesSize; i++) {
changed |= addRoleName(roleNames.get(i));
}
if (changed) {
// 保存在本地文件
scheduleWriteFileLocked();
}
}
}
...
/**
* Adds the given role, effectively marking it as {@link #isRoleAvailable available}
*
* @param roleName the name of the role
*
* @return whether any changes were made
*/
public boolean addRoleName(@NonNull String roleName) {
synchronized (mLock) {
if (!mRoles.containsKey(roleName)) {
// 向mRoles中添加数据
mRoles.put(roleName, new ArraySet<>());
Slog.i(LOG_TAG, "Added new role: " + roleName);
scheduleWriteFileLocked();
return true;
} else {
return false;
}
}
}
开机加载默认支持的role基本就是这样了
2.判断是否是Default Dialer
在暗码启动(一)中有提到,输入暗码后会对版本和是否是默认Dialer应用进行判断
- packages/apps/Dialer/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
public static void handleSecretCode(Context context, String secretCode) {
// Must use system service on O+ to avoid using broadcasts, which are not allowed on O+.
if (BuildCompat.isAtLeastO()) {
if (!TelecomUtil.isDefaultDialer(context)) {
LogUtil.e(
"TelephonyManagerCompat.handleSecretCode",
"not default dialer, cannot send special code");
return;
}
context.getSystemService(TelephonyManager.class).sendDialerSpecialCode(secretCode);
} else {
// System service call is not supported pre-O, so must use a broadcast for N-.
Intent intent =
new Intent(SECRET_CODE_ACTION, Uri.parse("android_secret_code://" + secretCode));
context.sendBroadcast(intent);
}
}
如果不是默认的Dialer应用直接返回不处理,抓取的log中也有not default dialer字样,所以说当前使用的Dialer应用不是默认的,就没有继续往下走。
看下是怎么判定default dialer,追踪流程如下:
- packages/apps/Dialer/java/com/android/dialer/telecom/TelecomUtil.java
public boolean isDefaultDialer(Context context) {
final boolean result =
TextUtils.equals(
context.getPackageName(), getTelecomManager(context).getDefaultDialerPackage());
if (result) {
warningLogged = false;
} else {
if (!warningLogged) {
// Log only once to prevent spam.
LogUtil.w(TAG, "Dialer is not currently set to be default dialer");
warningLogged = true;
}
}
return result;
}
从TelecomManager中获取getDefaultDialerPackage(),然后又调用到TelecomServiceImpl中的getDefaultDialerPackage()。
- packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java
@Override
public String getDefaultDialerPackage() {
try {
Log.startSession("TSI.gDDP");
final long token = Binder.clearCallingIdentity();
try {
return mDefaultDialerCache.getDefaultDialerApplication(
ActivityManager.getCurrentUser());
} finally {
Binder.restoreCallingIdentity(token);
}
} finally {
Log.endSession();
}
}
- packages/services/Telecomm/src/com/android/server/telecom/DefaultDialerCache.java
public String getDefaultDialerApplication(int userId) {
if (userId == UserHandle.USER_CURRENT) {
userId = ActivityManager.getCurrentUser();
}
if (userId < 0) {
Log.w(LOG_TAG, "Attempting to get default dialer for a meta-user %d", userId);
return null;
}
// TODO: Re-enable this when we are able to use the cache once more. RoleManager does not
// provide a means for being informed when the role holder changes at the current time.
//
//synchronized (mLock) {
// String defaultDialer = mCurrentDefaultDialerPerUser.get(userId);
// if (defaultDialer != null) {
// return defaultDialer;
// }
//}
return refreshCacheForUser(userId);
}
...
private String refreshCacheForUser(int userId) {;
String currentDefaultDialer =
mRoleManagerAdapter.getDefaultDialerApp(userId);
synchronized (mLock) {
mCurrentDefaultDialerPerUser.put(userId, currentDefaultDialer);
}
return currentDefaultDialer;
}
RoleManagerAdapter是一个接口类,具体方法实现在RoleManagerAdapterImpl中
- packages/services/Telecomm/src/com/android/server/telecom/RoleManagerAdapterImpl.java
@Override
public String getDefaultDialerApp(int user) {
if (mOverrideDefaultDialerApp != null) {
return mOverrideDefaultDialerApp;
}
return getRoleManagerDefaultDialerApp(user);
}
...
// 通过ROLE_DIALER获取默认Dialer应用包名;
private String getRoleManagerDefaultDialerApp(int user) {
List<String> roleHolders = mRoleManager.getRoleHoldersAsUser(ROLE_DIALER,
new UserHandle(user));
if (roleHolders == null || roleHolders.isEmpty()) {
return null;
}
return roleHolders.get(0);
}
从这里可以看出是从RoleManager中获取名称为ROLE_DIALER的dialer应用包名。
ROLE_DIALER = android.app.role.DIALER
又从RoleManager的getRoleHoldersAsUser()方法,调用到服务RoleManagerService中的getRoleHoldersAsUser()
- frameworks/base/services/core/java/com/android/server/role/RoleManagerService.java
@NonNull
@Override
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
return Collections.emptyList();
}
userId = handleIncomingUser(userId, false, "getRoleHoldersAsUser");
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"getRoleHoldersAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
if (roleHolders == null) {
return Collections.emptyList();
}
return new ArrayList<>(roleHolders);
}
...
@NonNull
private RoleUserState getOrCreateUserState(@UserIdInt int userId) {
synchronized (mLock) {
RoleUserState userState = mUserStates.get(userId);
if (userState == null) {
userState = new RoleUserState(userId, this);
mUserStates.put(userId, userState);
}
return userState;
}
}
- frameworks/base/services/core/java/com/android/server/role/RoleUserState.java
@Nullable
public ArraySet<String> getRoleHolders(@NonNull String roleName) {
synchronized (mLock) {
// 通过传过来的android.app.role.DIALER获取包名
ArraySet<String> packageNames = mRoles.get(roleName);
if (packageNames == null) {
return null;
}
return new ArraySet<>(packageNames);
}
}
这个mRoles就是最开始通过解析xml得到的,包含所有可用的role。但是这里返回为null,说明mRoles中没有这个role,android.app.role.DIALER不可用了。
roles.xml中Dialer相关代码
- packages/apps/PermissionController/res/xml/roles.xml
<role
name="android.app.role.DIALER"
behavior="DialerRoleBehavior" // Dialer应用使用
defaultHolders="config_defaultDialer"
description="@string/role_dialer_description"
exclusive="true"
fallBackToDefaultHolder="true"
label="@string/role_dialer_label"
requestDescription="@string/role_dialer_request_description"
requestTitle="@string/role_dialer_request_title"
searchKeywords="@string/role_dialer_search_keywords"
shortLabel="@string/role_dialer_short_label">
<required-components>
再看DialerRoleBehavior继承自RoleBehavior
- packages/apps/PermissionController/src/com/android/permissioncontroller/role/model/DialerRoleBehavior.java
@Override
public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
@NonNull Context context) {
TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
return telephonyManager.isVoiceCapable();
}
- frameworks/base/telephony/java/android/telephony/TelephonyManager.java
public boolean isVoiceCapable() {
if (mContext == null) return true;
return mContext.getResources().getBoolean(
com.android.internal.R.bool.config_voice_capable);
}
看到这里找到原因了,我们的项目不支持通话,把config_voice_capable设为false了,所以导致RoleManager.ROLE_DIALER = android.app.role.DIALER这个role不可用。