项目中系统自带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不可用。