[SystemServer] AccountManagerService 浅析

前言

这篇文章主要简单分析下AccountManagerService,首先我们要有个基本的认识,就是AccountManagerSrevice是干什么的?下意识的会觉得这是个管理用户的service,其实不然,AccountManagerService其实是用来管理"账户"的,比如你的Email,微博,Facebook账户,而用户在账户之上,用户含有账户。

有了以上的基本共识,我们来开始看下源码:

源码

在SystemServer的run方法中启动services

      // Start services.
        try {
            traceBeginAndSlog("StartServices")
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        }

AccountManagerService位于startOtherServices()方法中,可见其并不是系统的关键服务,startOtherServices中启动AccountManagerService的代码如下:

            // The AccountManager must come before the ContentService
            traceBeginAndSlog("StartAccountManagerService");
            mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS);
            traceEnd();

其中ACCOUNT_SERVICE_CLASS为:

    private static final String ACCOUNT_SERVICE_CLASS =
            "com.android.server.accounts.AccountManagerService$Lifecycle";

可以看到,真正启动的service封装其实是AccountManagerService中Lifecycle内部类,这种方式是SystemServer中启动services的通用方法。而在SystemServiceManager类中,经过系列转换是回掉类型位SystemService的onStart方法,可见Lifecycle内部类肯定是SystemService的子类了。

    public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            //回掉service的onStart方法开始启动Service
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    }

再看AccountManagerService中的实现,首先是Lifecycle内部类:

    public static class Lifecycle extends SystemService {
        private AccountManagerService mService;
        public Lifecycle(Context context) {
            super(context);
        }
        @Override
        public void onStart() {
            mService = new AccountManagerService(new Injector(getContext()));
            publishBinderService(Context.ACCOUNT_SERVICE, mService);
        }
        @Override
        public void onUnlockUser(int userHandle) {
            mService.onUnlockUser(userHandle);
        }
        @Override
        public void onStopUser(int userHandle) {
            Slog.i(TAG, "onStopUser " + userHandle);
            mService.purgeUserData(userHandle);
        }
    }

果然继承了SystemService,前面讲到启动SystemService是通过会调onStart方法的形式,那么AccountManagerService中的onStart做了什么:

        @Override
        public void onStart() {
            mService = new AccountManagerService(new Injector(getContext()));
            publishBinderService(Context.ACCOUNT_SERVICE, mService);
        }

在这里publishBinderService主要是将这个service添加到ServiceManager这个服务管家中,那么AccountManagerService初始化的关键就是它的构造函数了,首先是Injector类:

    static class Injector {
        private final Context mContext;

        public Injector(Context context) {
            mContext = context;
        }

        //这里会启动一个线程,并返回其looper
        Looper getMessageHandlerLooper() {
            ServiceThread serviceThread = new ServiceThread(TAG,
                    android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
            serviceThread.start();
            return serviceThread.getLooper();
        }

        Context getContext() {
            return mContext;
        }
             //添加服务到LocalServices中
        void addLocalService(AccountManagerInternal service) {
            LocalServices.addService(AccountManagerInternal.class, service);
        }
               //获取设备加密存储数据库名称
        String getDeDatabaseName(int userId) {
            File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
                    AccountsDb.DE_DATABASE_NAME);
            return databaseFile.getPath();
        }
               //获取凭据加密存储数据库名称
        String getCeDatabaseName(int userId) {
            File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
                    AccountsDb.CE_DATABASE_NAME);
            return databaseFile.getPath();
        }
               //获取Android N之前的数据库名称
        String getPreNDatabaseName(int userId) {
            File systemDir = Environment.getDataSystemDirectory();
            File databaseFile = new File(Environment.getUserSystemDirectory(userId),
                    PRE_N_DATABASE_NAME);
            if (userId == 0) {
                // Migrate old file, if it exists, to the new location.
                // Make sure the new file doesn't already exist. A dummy file could have been
                // accidentally created in the old location,
                // causing the new one to become corrupted as well.
                File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
                if (oldFile.exists() && !databaseFile.exists()) {
                    // Check for use directory; create if it doesn't exist, else renameTo will fail
                    File userDir = Environment.getUserSystemDirectory(userId);
                    if (!userDir.exists()) {
                        if (!userDir.mkdirs()) {
                            throw new IllegalStateException(
                                    "User dir cannot be created: " + userDir);
                        }
                    }
                    if (!oldFile.renameTo(databaseFile)) {
                        throw new IllegalStateException(
                                "User dir cannot be migrated: " + databaseFile);
                    }
                }
            }
            return databaseFile.getPath();
        }

        IAccountAuthenticatorCache getAccountAuthenticatorCache() {
            return new AccountAuthenticatorCache(mContext);
        }

        INotificationManager getNotificationManager() {
            return NotificationManager.getService();
        }
    }

从Injector类的代码可以看出,它主要是创建了一个线程,提供了获取几个数据库名称的api接口。值得一提的是这里的两个数据库:credential encryption database 和 device encryption database,它们代表了每个用户在Android N之后的可使用的加密存储位置:
1、CE(credential encryption)凭据加密存储空间:默认存储空间,只有在用户解锁设备后才可用,对应存储位置:/data/system_ce/0/accounts_ce.db
2、DE(device encryption)设备加密存储空间:在direct root模式下以及用户解锁设备后均可用,对应存储位置:/data/system_de/0/accounts_de.db
这里的direct root代表用户开机但是还没解锁。而在Android N之前没有de和ce的区别,加密存储位置为:/data/system/users/0/accounts.db

我们继续看AccountManagerService的构造函数:

public AccountManagerService(Injector injector) {
        mInjector = injector;
        mContext = injector.getContext();
        mPackageManager = mContext.getPackageManager();
        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
        // 这里通过injector启动线程并且创建Handler实例
        mHandler = new MessageHandler(injector.getMessageHandlerLooper());
        mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
        mAuthenticatorCache.setListener(this, null /* Handler */);

        sThis.set(this);
        // 注册监听器监听PACKAGE_REMOVED事件,以在必要时清空相应数据。
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addDataScheme("package");
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context1, Intent intent) {
                // Don't delete accounts when updating a authenticator's
                // package.
                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                    final String removedPackageName = intent.getData().getSchemeSpecificPart();
                    Runnable purgingRunnable = new Runnable() {
                        @Override
                        public void run() {
                            purgeOldGrantsAll();
                            // Notify authenticator about removed app?
                            removeVisibilityValuesForPackage(removedPackageName);
                        }
                    };
                    mHandler.post(purgingRunnable);
                }
            }
        }, intentFilter);

        injector.addLocalService(new AccountManagerInternalImpl());
        // 注册监听器,监听USER_REMOVED事件,以在必要时清楚用户数据
        IntentFilter userFilter = new IntentFilter();
        userFilter.addAction(Intent.ACTION_USER_REMOVED);
        mContext.registerReceiverAsUser(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (Intent.ACTION_USER_REMOVED.equals(action)) {
                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                    if (userId < 1) return;
                    Slog.i(TAG, "User " + userId + " removed");
                    purgeUserData(userId);
                }
            }
        }, UserHandle.ALL, userFilter, null, null);
        //...
    }

从其构造函数来看AccountManagerService主要是通过Injector初始化了一些实例,并且监听了一些事件。回到AccountManagerService的本质,作为FrameWork 中的一个系统service,我们可以思考一下这些service是怎么工作的?我想来想去:下面两种可能是主要的工作模式:

1、通过进程间或是线程间通信接收来自客户端的消息,处理并返回。

2、通过实现会调方法或是监听广播事件,在必要时刻做些工作。

那么这样的职能和可能涉及多个模块的交互,如何讲明白,其实我觉得画图是很好的方法。

我个人偏好画一些类图和结构图,因为框架性的类设计和结构画清楚了,对其的运作也就了解的差不多了,如果在wiki中,这样的图就尤其适合了。

前面看了AccountManagerService在系统中的位置及其初始化阶段都做了哪些事情,下面根据一张图,我们来看看它的强关系及它是如何与其它相关的类关联起来的:


[SystemServer] AccountManagerService 浅析_第1张图片
AccountManagerService

从AccountManagerService的强关系中,我们可以看到它继承了IAccountManager.Stub是IAccountManager的Bn端,实现了RegisteredServicesCacheListener,同时它位于framework的com.android.server的包中。 那么按照我们我们之前讲的,位于另一个包中的AccountManager因为持有IAccountManager Bp端(见图中的红色proxy字体),它会向AccountManagerService发送消息,而又实现了RegisteredServicesCacheListener,说明RegisteredServicesCacheListener中的方法也会在某一个时机回掉到AccountManagerService中。

这样的设计看起来很常见,也好理解。那AccountManager都向AccountManagerService发了什么样的消息呢? 我们从AccountManager的功能出发,作为一个提供账户管理的服务,增删账户肯定是基础功能。下面从增加账户作为切入口:

账户管理

1、AccountManager 新起一个异步Task, 通过Binder调用到AccountManagerService中的内部类Session,将AccountManager中的Response实例作为变量传递过去以备后面通知结果。

 new AmsTask(activity, handler, callback) {
            @Override
            public void doWork() throws RemoteException {
                mService.addAccount(mResponse, accountType, authTokenType,
                        requiredFeatures, activity != null, optionsIn);
            }
        }.start();

2、Session本身是IAccountAuthenticatorResponse的Bn端,同时内部持有IAccountAuthenticator的Bp端
Session部分代码:

// 继承IAccountAuthenticatorResponse.Stub
    private abstract class Session extends IAccountAuthenticatorResponse.Stub
            implements IBinder.DeathRecipient, ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        // 持有IAccountAuthenticator的Bp端
            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
            try {
                run();
            } catch (RemoteException e) {
                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
                        "remote exception");
            }
        }

3、Session通过调用IAccountAuthenticator的Bp接口,让AccountAuthenticator完成实际的添加账户的动作。

new Session(accounts, response, accountType, expectActivityLaunch,
                    true /* stripAuthTokenFromResult */, null /* accountName */,
                    false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
                @Override
                public void run() throws RemoteException {
                // Session调用IAccountAuthenticator的bp接口
                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
                            options);
                }

                @Override
                protected String toDebugString(long now) {
                    return super.toDebugString(now) + ", addAccount"
                            + ", accountType " + accountType
                            + ", requiredFeatures " + Arrays.toString(requiredFeatures);
                }
            }.bind();

4、AccountAuthenticator 完成后通过IAccountAuthenticatorResponse Bp端通知其Bn端也就是Session,Session 再通过2步的Response实例通知回AccountManager。

注意图中Session类所在的一个闭环。

数据库操作

前面我们提过AccountManagerService 实现了RegisteredServicesCacheListener接口,那么此接口中的方法肯定会在一定条件下回调到AccountManagerService中。而且值得注意的是RegisteredServicesCacheListener 和图中的RegisteredServicesCache都在pm包中,引人思考。

1、Inject类创建AccountAuthenticatorCache实例,AccountAuthenticatorCache实例setListener

 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
        mAuthenticatorCache.setListener(this, null /* Handler */);

2、AccountAuthenticatorCache继承的RegisteredServicesCache在监听package的add remove等事件。

RegisteredServicesCache的构造函数内:
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addDataScheme("package");
        mContext.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, intentFilter, null, null);

        // Register for events related to sdcard installation.
        IntentFilter sdFilter = new IntentFilter();
        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
        mContext.registerReceiver(mExternalReceiver, sdFilter);

3、一旦package的add remove发生,RegisteredServicesCache开始回调Listener,AccountManagerService中的实现被调用

//RegisteredServicesCache 内通知Listener
        handler.post(new Runnable() {
            public void run() {
                listener2.onServiceChanged(type, userId, removed);
            }
        });

//AccountManagerService中的实现
    @Override
    public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
        validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
    }

4、AccountManagerService中实现的方法是在更新用户数据库。

private void validateAccountsInternal(
            UserAccounts accounts, boolean invalidateAuthenticatorCache) {

        if (invalidateAuthenticatorCache) {
            mAuthenticatorCache.invalidateCache(accounts.userId);
        }

        final HashMap knownAuth = getAuthenticatorTypeAndUIDForUser(
                mAuthenticatorCache, accounts.userId);
        boolean userUnlocked = isLocalUnlockedUser(accounts.userId);

        synchronized (accounts.dbLock) {
            synchronized (accounts.cacheLock) {
                boolean accountDeleted = false;
               // 获取DB实例
               final AccountsDb accountsDb = accounts.accountsDb;
                Map metaAuthUid = accountsDb.findMetaAuthUid();
                // Create a list of authenticator type whose previous uid no longer exists
                HashSet obsoleteAuthType = Sets.newHashSet();
                SparseBooleanArray knownUids = null;
                for (Entry authToUidEntry : metaAuthUid.entrySet()) {
                    String type = authToUidEntry.getKey();
                    int uid = authToUidEntry.getValue();
                    Integer knownUid = knownAuth.get(type);
                    if (knownUid != null && uid == knownUid) {
                        // Remove it from the knownAuth list if it's unchanged.
                        knownAuth.remove(type);
                    } else {
                        if (knownUids == null) {
                            knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
                        }
                        if (!knownUids.get(uid)) {
                            // The authenticator is not presently available to the cache. And the
                            // package no longer has a data directory (so we surmise it isn't
                            // updating). So purge its data from the account databases.
                            obsoleteAuthType.add(type);
                            //DB 操作                            
                            accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
                        }
                    }
                }

               for (Entry entry : knownAuth.entrySet()) {
                     // DB操作
                    accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
                }

                final Map accountsMap = accountsDb.findAllDeAccounts();
                try {
                    accounts.accountCache.clear();
                    final HashMap> accountNamesByType
                            = new LinkedHashMap<>();
                    for (Entry accountEntry : accountsMap.entrySet()) {
                        final long accountId = accountEntry.getKey();
                        final Account account = accountEntry.getValue();
                        if (obsoleteAuthType.contains(account.type)) {
                           Map packagesToVisibility =
                                    getRequestingPackages(account, accounts);
                            List accountRemovedReceivers =
                                getAccountRemovedReceivers(account, accounts);
                            // DB操作
                            accountsDb.beginTransaction();
                            try {
                                accountsDb.deleteDeAccount(accountId);
                               if (userUnlocked) {
                                    accountsDb.deleteCeAccount(accountId);
                                }
                                accountsDb.setTransactionSuccessful();
                            } finally {
                                accountsDb.endTransaction();
                            }
                            accountDeleted = true;

                            logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
                                    AccountsDb.TABLE_ACCOUNTS, accountId, accounts);

                            accounts.userDataCache.remove(account);
                            accounts.authTokenCache.remove(account);
                            accounts.accountTokenCaches.remove(account);
                            accounts.visibilityCache.remove(account);

                            for (Entry packageToVisibility :
                                    packagesToVisibility.entrySet()) {
                                if (isVisible(packageToVisibility.getValue())) {
                                    notifyPackage(packageToVisibility.getKey(), accounts);
                                }
                            }
                            for (String packageName : accountRemovedReceivers) {
                                sendAccountRemovedBroadcast(account, packageName, accounts.userId);
                            }
                        } else {
                            ArrayList accountNames = accountNamesByType.get(account.type);
                            if (accountNames == null) {
                                accountNames = new ArrayList<>();
                                accountNamesByType.put(account.type, accountNames);
                            }
                            accountNames.add(account.name);
                        }
                    }
                    for (Map.Entry> cur : accountNamesByType.entrySet()) {
                        final String accountType = cur.getKey();
                        final ArrayList accountNames = cur.getValue();
                        final Account[] accountsForType = new Account[accountNames.size()];
                        for (int i = 0; i < accountsForType.length; i++) {
                            accountsForType[i] = new Account(accountNames.get(i), accountType,
                                    UUID.randomUUID().toString());
                        }
                        accounts.accountCache.put(accountType, accountsForType);
                    }
                    accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
                } finally {
                    if (accountDeleted) {
                        sendAccountsChangedBroadcast(accounts.userId);
                    }
                }
            }
        }
    }

注意图中AccountAuthenticatorCache所在的一个闭环

总结

AccountManagerService作为一个轻量级service,总得来说比较简单。但是他对数据库的频繁操作(触发条件比较容易),容易让它为用户目录或用户管理发生的错误背锅,错误不是它造成的,但是有大几率出现在它这。后续在分析问题案例和service时还会提到它。

你可能感兴趣的:([SystemServer] AccountManagerService 浅析)