基于N源码的AccountManagerService简单认识和账户添加流程分析
来源:互联网 发布:java map中文乱码 编辑:程序博客网 时间:2024/05/21 17:55
AccountManagerService负责管理手机中用户的在线账户,主要的工作涉及账户的添加、删除和AuthToken的获取和更新。
下面看下AccountManagerService的初始化,进入SystemServer中的startOtherServices方法看到如下代码:
mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS);
其中ACCOUNT_SERVICE_CLASS为com.android.server.accounts.AccountManagerService$Lifecycle,SystemServiceManager的startService里面会通过反射创建AccountManagerService.Lifecycle对象,并调用其onStart方法:
public void onStart() { mService = new AccountManagerService(getContext()); publishBinderService(Context.ACCOUNT_SERVICE, mService); }
可以看到创建AccountManagerService对象,并发布到服务总管里面。下面看下AccountManagerService构造函数:
public AccountManagerService(Context context) { this(context, context.getPackageManager(), new AccountAuthenticatorCache(context)); } public AccountManagerService(Context context, PackageManager packageManager, IAccountAuthenticatorCache authenticatorCache) { mContext = context; mPackageManager = packageManager; mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mMessageHandler = new MessageHandler(FgThread.get().getLooper()); mAuthenticatorCache = authenticatorCache; mAuthenticatorCache.setListener(this, null /* Handler */);
这里又创建了AccountAuthenticatorCache对象并设置监听器,AccountAuthenticatorCache是android平台中账户验证服务(AAS)的管理中心,AAS是应用程序中定义的服务,对它的定义有一定的要求,后面会看到。接着看下AccountAuthenticatorCache的构造函数:
/* package private */ class AccountAuthenticatorCache extends RegisteredServicesCache<AuthenticatorDescription> public AccountAuthenticatorCache(Context context) { super(context, AccountManager.ACTION_AUTHENTICATOR_INTENT, AccountManager.AUTHENTICATOR_META_DATA_NAME, AccountManager.AUTHENTICATOR_ATTRIBUTES_NAME, sSerializer); }
这里又调用父类RegisteredServicesCache构造函数,传递的参数如下定义:
public static final String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator"; public static final String AUTHENTICATOR_META_DATA_NAME = "android.accounts.AccountAuthenticator"; public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
后面解析XML要用到,所以AAS的配置文件也需要符合这个要求。
public RegisteredServicesCache(Context context, String interfaceName, String metaDataName, String attributeName, XmlSerializerAndParser<V> serializerAndParser) { mContext = context; mInterfaceName = interfaceName; mMetaDataName = metaDataName; mAttributesName = attributeName; mSerializerAndParser = serializerAndParser; migrateIfNecessaryLocked(); 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);
简单看下RegisteredServicesCache构造函数,其中migrateIfNecessaryLocked用户在系统目录下创建文件:
File systemDir = new File(getDataDirectory(), "system"); File syncDir = new File(systemDir, REGISTERED_SERVICES_DIR); AtomicFile oldFile = new AtomicFile(new File(syncDir, mInterfaceName + ".xml"));
接着注册了包添加删除广播。猜测应用安装或卸载会在这里进行账户信息添加和删除。下面看下这个广播接收器:
private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); if (uid != -1) { handlePackageEvent(intent, UserHandle.getUserId(uid)); } } };
接着进入handlePackageEvent:
private final void handlePackageEvent(Intent intent, int userId) { // Don't regenerate the services map when the package is removed or its // ASEC container unmounted as a step in replacement. The subsequent // _ADDED / _AVAILABLE call will regenerate the map in the final state. final String action = intent.getAction(); // it's a new-component action if it isn't some sort of removal final boolean isRemoval = Intent.ACTION_PACKAGE_REMOVED.equals(action) || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action); // if it's a removal, is it part of an update-in-place step? final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); if (isRemoval && replacing) { // package is going away, but it's the middle of an upgrade: keep the current // state and do nothing here. This clause is intentionally empty. } else { int[] uids = null; // either we're adding/changing, or it's a removal without replacement, so // we need to update the set of available services if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { uids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); } else { int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); if (uid > 0) { uids = new int[] { uid }; } } generateServicesMap(uids, userId); }
当包正在删除且部分在更新情况不做任何处理,接着进入generateServicesMap:
private void generateServicesMap(int[] changedUids, int userId) { if (DEBUG) { Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + changedUids); } final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>(); final List<ResolveInfo> resolveInfos = queryIntentServices(userId); for (ResolveInfo resolveInfo : resolveInfos) { try { ServiceInfo<V> info = parseServiceInfo(resolveInfo); if (info == null) { Log.w(TAG, "Unable to load service info " + resolveInfo.toString()); continue; } serviceInfos.add(info); } catch (XmlPullParserException|IOException e) { Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); } }
首先传递userid通过PMS查询应用包服务信息。接着通过parseServiceInfo解析服务信息:
protected ServiceInfo<V> parseServiceInfo(ResolveInfo service) throws XmlPullParserException, IOException { android.content.pm.ServiceInfo si = service.serviceInfo; ComponentName componentName = new ComponentName(si.packageName, si.name); PackageManager pm = mContext.getPackageManager(); XmlResourceParser parser = null;parser = si.loadXmlMetaData(pm, mMetaDataName);AttributeSet attrs = Xml.asAttributeSet(parser);V v = parseServiceAttributes(pm.getResourcesForApplication(si.applicationInfo),si.packageName, attrs);if (v == null) {return null;}final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo;return new ServiceInfo<V>(v, serviceInfo, componentName); }
解析MetaData信息,接着调用子类parseServiceAttributes来解析MetaData中的resource信息。
public AuthenticatorDescription parseServiceAttributes(Resources res, String packageName, AttributeSet attrs) { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AccountAuthenticator); try { final String accountType = sa.getString(com.android.internal.R.styleable.AccountAuthenticator_accountType); final int labelId = sa.getResourceId( com.android.internal.R.styleable.AccountAuthenticator_label, 0); final int iconId = sa.getResourceId( com.android.internal.R.styleable.AccountAuthenticator_icon, 0); final int smallIconId = sa.getResourceId( com.android.internal.R.styleable.AccountAuthenticator_smallIcon, 0); final int prefId = sa.getResourceId( com.android.internal.R.styleable.AccountAuthenticator_accountPreferences, 0); final boolean customTokens = sa.getBoolean( com.android.internal.R.styleable.AccountAuthenticator_customTokens, false); if (TextUtils.isEmpty(accountType)) { return null; } return new AuthenticatorDescription(accountType, packageName, labelId, iconId, smallIconId, prefId, customTokens); } finally { sa.recycle(); } }
MetaData的resource一般是xml文件,下面举例SimContact模块中的AAS(SimAuthenticateService),看下它的配置文件和MetaDta的resource:
sim_authenticator.xml文件如下
上面xml文件中的accountType标签用于指定账户类型,icon、smallIcon、label等用于界面显示。最终将sim_authenticator文件解析封装到AuthenticatorDescription对象中返回。
关于AccountManagerService的认识就先了解到这,下面重点分析下添加账户的过程。一般默认添加账户都是在设置里面添加,应用程序也可以自己添加。添加账户入口在AccountManager类的addAccount:
public AccountManagerFuture<Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { return new AmsTask(activity, handler, callback) { @Override public void doWork() throws RemoteException { mService.addAccount(mResponse, accountType, authTokenType, requiredFeatures, activity != null, optionsIn); } }.start(); }
这里返回AmsTask对象,这是什么鬼?
private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> { final IAccountManagerResponse mResponse; final Handler mHandler; final AccountManagerCallback<Bundle> mCallback; final Activity mActivity; public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) { super(new Callable<Bundle>() { @Override public Bundle call() throws Exception { throw new IllegalStateException("this should never be called"); } }); mHandler = handler; mCallback = callback; mActivity = activity; mResponse = new Response(); } public final AccountManagerFuture<Bundle> start() { try { doWork(); } catch (RemoteException e) { setException(e); } return this; }public abstract void doWork() throws RemoteException; private class Response extends IAccountManagerResponse.Stub { @Override public void onResult(Bundle bundle) { Intent intent = bundle.getParcelable(KEY_INTENT); mActivity.startActivity(intent); } @Override public void onError(int code, String message) { } }
它继承FutureTask实现AccountManagerFuture,关于FutureTask介绍可查看链接 FutureTask 深度解析,构造函数里面还创建了Response对象,它继承IAccountManagerResponse.Stub,根据经验它是服务的实现者,用于响应AccountManagerService的回调。接着调用start-》dowork()进入到AccountManagerService中的addAccount:
public void addAccount(final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn) { UserAccounts accounts = getUserAccounts(usrId); logRecordWithUid( accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, uid); new Session(accounts, response, accountType, expectActivityLaunch, true /* stripAuthTokenFromResult */, null /* accountName */, false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) { @Override public void run() throws RemoteException { mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures, options); } @Override protected String toDebugString(long now) { return super.toDebugString(now) + ", addAccount" + ", accountType " + accountType + ", requiredFeatures " + (requiredFeatures != null ? TextUtils.join(",", requiredFeatures) : null); } }.bind();}
这里创建了一个Session对象,这又是什么鬼?
private abstract class Session extends IAccountAuthenticatorResponse.Stub implements IBinder.DeathRecipient, ServiceConnection { IAccountManagerResponse mResponse;IAccountAuthenticator mAuthenticator = null; public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType, boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName, boolean authDetailsRequired, boolean updateLastAuthenticatedTime) { super(); mAccounts = accounts; mResponse = response; mAccountType = accountType; mAccountName = accountName; synchronized (mSessions) { mSessions.put(toString(), this); } } void bind() { if (!bindToAuthenticator(mAccountType)) { } } public void onServiceConnected(ComponentName name, IBinder service) { mAuthenticator = IAccountAuthenticator.Stub.asInterface(service); run(); }public abstract void run() throws RemoteException;public void onResult(Bundle result) {} private boolean bindToAuthenticator(String authenticatorType) { final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo; authenticatorInfo = mAuthenticatorCache.getServiceInfo( AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId); Intent intent = new Intent(); intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT); intent.setComponent(authenticatorInfo.componentName); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName); } if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE, UserHandle.of(mAccounts.userId))) { } return true; } }
它继承IAccountAuthenticatorResponse.Stub,是服务的实现者,跟谁通信?后面再看,又实现ServiceConnection,感觉在绑定服务的时候见过。接着调用bind()-》bindToAuthenticator,这里通过mAuthenticatorCache获取服务信息,mAuthenticatorCache在前面认识AccountManagerService介绍过。获取到ServiceInfo信息就开始绑定服务。这里以SimAuthenticateService为例,bindServiceAsUser调用后就会调用它的onBind方法:
这里的SimAuthenticator继承AbstractAccountAuthenticator,返回它的getIBinder(),其实是AbstractAccountAuthenticator中的内部类Transport对象的binder对象:
private Transport mTransport = new Transport(); /** * @return the IBinder for the AccountAuthenticator */ public final IBinder getIBinder() { return mTransport.asBinder(); }
private class Transport extends IAccountAuthenticator.Stub { @Override public void addAccount(IAccountAuthenticatorResponse response, String accountType,
可见Transport又是服务的实现者,猜测在AccountManagerService会调用。
回到上面AccountManagerService中的添加服务流程中,刚才走到绑定服务,绑定成功会调用onServiceConnected函数,该函数中获取服务代理对象:
mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
接着run:
public void run() throws RemoteException { mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures, options); }
mAuthenticator为本地代理对象,调用addAccount会根据binder机制进入服务的实现者,也就是AbstractAccountAuthenticator中的内部类Transport:
final Bundle result = AbstractAccountAuthenticator.this.addAccount( new AccountAuthenticatorResponse(response)
if (result != null) { response.onResult(result); }
这里调用AbstractAccountAuthenticator的子类,也就是上面举例的SimAuthenticator,注意上面传递的IAccountAuthenticatorResponse 的binder对象response,它的真正实现者在AccountManagerService内部类Session(private abstract class Session extends IAccountAuthenticatorResponse.Stub),也就是说这里调用response.onResult(result);又回到了Session中:
public void onResult(Bundle result) { IAccountManagerResponse response; response = mResponse; if (response != null) { response.onResult(result); } }
这里的response又是个binder对象。额,已经晕了。仔细回忆,它是在AccountManager的addAccount传递进来的,它是AmsTask的内部类Response:
private class Response extends IAccountManagerResponse.Stub { @Override public void onResult(Bundle bundle) { Intent intent = bundle.getParcelable(KEY_INTENT); if (intent != null && mActivity != null) { // since the user provided an Activity we will silently start intents // that we see mActivity.startActivity(intent);
整个流程差不多介绍完了。最后看下SimAuthenticator是如何添加服务的,它调用AccountManager的addAccountExplicitly:
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) { if (account == null) throw new IllegalArgumentException("account is null"); try { return mService.addAccountExplicitly(account, password, userdata); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
直接进入AccountManagerService的addAccountExplicitly:
public boolean addAccountExplicitly(Account account, String password, Bundle extras) { UserAccounts accounts = getUserAccounts(userId); return addAccountInternal(accounts, account, password, extras, callingUid);}
进入addAccountInternal:
private boolean addAccountInternal(UserAccounts accounts, Account account, String password, Bundle extras, int callingUid) { final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked(); db.beginTransaction(); ContentValues values = new ContentValues(); values.put(ACCOUNTS_NAME, account.name); values.put(ACCOUNTS_TYPE, account.type); values.put(ACCOUNTS_PASSWORD, password); long accountId = db.insert(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values); values = new ContentValues(); values.put(ACCOUNTS_ID, accountId); values.put(ACCOUNTS_NAME, account.name); values.put(ACCOUNTS_TYPE, account.type); values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis()); if (db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values) < 0) db.endTransaction(); } sendAccountsChangedBroadcast(accounts.userId);这里做了添加数据库的操作和发送账户修改广播。
最后贴一张添加服务的流程图:
- 基于N源码的AccountManagerService简单认识和账户添加流程分析
- 基于N源码的广播注册和发送流程分析
- 基于Andoird 4.2.2的Account Manager源代码分析学习:AccountManagerService系统服务的添加
- 基于N源码的ContentProvider调用流程分析
- Activity的绘制流程简单分析(基于android 4.0源码进行分析)
- 简单Rxjava订阅的源码流程分析
- android系统账户管理(AccountManagerService+AccountAuthenticator)
- 基于N源码的Activity的启动过程分析
- android 联系人源码分析 新字段的添加流程
- Android基于源码分析AsyncTask的工作流程
- 基于N源码Service启动分析
- Launcher3源码分析之Widget添加流程
- Fragment之添加显示流程源码分析
- struts2流程和源码分析
- 简单分析Android中添加shortcut方面的源码
- 简单分析Android中添加shortcut方面的源码 .
- 简单分析Android中添加shortcut方面的源码
- 简单分析Android中添加shortcut方面的源码
- LeetCode-通配符模式串匹配
- VC配置文件读取和写入
- js中使用jsp脚本和el
- Android技术的网址资源集合,此贴不定期更新,2
- RecyclerView下拉刷新,滑动删除以及拖动变换位置
- 基于N源码的AccountManagerService简单认识和账户添加流程分析
- Android中实现不同文字颜色和图文混排的Span总结
- PHP防止表单重复提交
- ios 10问题的解决方法
- 静态代码块、构造代码块、局部代码块、构造方法的执行顺序
- 关于java源码在编译时提示:编码GBK的不可映射字符 的问题
- Android开发:清空缓存
- 南阳 oj 448 寻找最大数
- Cron表达式详解