前言
这篇文章主要简单分析下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在系统中的位置及其初始化阶段都做了哪些事情,下面根据一张图,我们来看看它的强关系及它是如何与其它相关的类关联起来的:
从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时还会提到它。