上篇粗略的分析android添加帳號的流程,本篇深刻的解析下執行步驟。先來看圖片,取自深刻理解android卷2:java
上圖詳細的分析了addAccount的流程,下面咱們結合源碼來理解它android
一、addAccount:其實這裏省略了一步,應該是客戶端addAccount——>AddAccountSettings.addAccount——>AccountManager.addAccount。咱們看下setting是如何到AccountManager:git
private void addAccount(String accountType) { ...... AccountManager.get(this).addAccount( accountType, null, /* authTokenType */ null, /* requiredFeatures */ addAccountOptions, null, mCallback, null /* handler */); mAddAccountCalled = true; } }
代碼直白的告訴咱們就是去調用AccountManager.addAccount(好像是廢話哎),但咱們深刻看get函數發現另有玄機github
public static AccountManager get(Context context) { if (context == null) throw new IllegalArgumentException("context is null"); return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); }
而對於getSystemService(xxx)來講就是ContextImpl對應的註冊函數微信
registerService(ACCOUNT_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(ACCOUNT_SERVICE); IAccountManager service = IAccountManager.Stub.asInterface(b); return new AccountManager(ctx, service); }})
public AccountManager(Context context, IAccountManager service, Handler handler) { mContext = context; mService = service; mMainHandler = handler; }
ok,也就是說AccountManager.get(this)去建立了一個包含IAccountManager.Stub.asInterface(實質爲AccountManagerService)的AccountManager.Proxy;這很重要下面會用到。app
2—五、這幾步都是在AccountManager.addAccount裏,代碼脈絡也很清晰就一塊兒解釋吧。ide
public AccountManagerFuture<Bundle> addAccount(final String accountType, ...... return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { mService.addAccount(mResponse, accountType, authTokenType, requiredFeatures, activity != null, optionsIn); } }.start(); }
建立AmsTask並start,而start函數實質是去執行doWork函數,故這裏是去執行mService.addAccount。這裏須要注意的是mResponse,它是在new AmsTask時被建立函數
mResponse = new Response();
Response是AmsTask的內部類且繼承自IAccountManagerResponse.Stub(重要)。源碼分析
6—十二、按流程是去執行mService.addAccount,上面分析到mService 爲AccountManagerService即AccountManagerService.addAccountui
public void addAccount(final IAccountManagerResponse response, final String accountType, ...... new Session(accounts, response, accountType, expectActivityLaunch, true /* stripAuthTokenFromResult */) { @Override public void run() throws RemoteException { mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures, options); } ...... } }.bind(); ......
能夠看到此函數中包含不少操做,咱們慢慢來剖析。
private abstract class Session extends IAccountAuthenticatorResponse.Stub implements IBinder.DeathRecipient, ServiceConnection { ......
Session的構造函數中初始化mResponse,看參數可知mResponse =AmsTask.mResponse
public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType, ...... mResponse = response; ...... IAccountManagerResponse response = mResponse; ......
Session是AccountManagerService內部抽象類,繼承IAccountAuthenticatorResponse.Stub且實現ServiceConnection接口,這樣才能調用下面的bind(第8步)函數。
void bind() { ...... if (!bindToAuthenticator(mAccountType)) { Log.d(TAG, "bind attempt failed for " + toDebugString()); onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure"); } }
private boolean bindToAuthenticator(StringauthenticatorType) { //從mAuthenticatorCache中查詢知足指定類型的服務信息 AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo = mAuthenticatorCache.getServiceInfo( AuthenticatorDescription.newKey(authenticatorType)); ...... Intentintent = new Intent(); intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT); //設置目標服務的ComponentName intent.setComponent(authenticatorInfo.componentName); //經過bindService啓動指定的服務,成功與否將經過第二個參數傳遞的 //ServiceConnection接口返回 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE, ...... }
這裏分2步走:查詢系統獲得咱們要添加帳戶類型(微信、微博、淘寶,這裏用retme pocApp裏的代碼來解釋,不熟悉概念的看資料2)的authenticatorInfo;bindServiceAsUser去bind微信帳號的service(此service就是pocApp裏的AuthenticationService)。而此時pocApp的AuthenticationService執行onBind(第9步)
package com.example.android.samplesync.authenticator; public IBinder onBind(Intent intent) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "getBinder()... returning the AccountAuthenticator binder for intent " + intent); } return mAuthenticator.getIBinder(); }
注意這裏返回的binder是mAuthenticator,而mAuthenticator是pocApp中的Authenticator(若是你不懂這些是什麼玩意,建議結合pocApp看資料2)。
class Authenticator extends AbstractAccountAuthenticator {
AbstractAccountAuthenticator類中有內部類繼承
private class Transport extends IAccountAuthenticator.Stub {
而在執行bindServiceAsUser後回去回調onServiceConnection函數(第10步),不清楚爲何要回調自行查資料。上面提到Session實現ServiceConnection接口,這裏直接調用Session.onServiceConnection。這裏的service就是onbind返回的Authenticator,故mAuthenticator = Authenticator
public void onServiceConnected(ComponentName name,IBinder service) { //獲得遠端AAS返回的IAccountAuthenticator接口,這個接口用於 //AccountManagerService和該遠端AAS交互 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service); try { run();//調用匿名Session類實現的run函數,看第6步中的匿名類函數 } ...... }
執行第11步 run
public void run() throws RemoteException { mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures, options); }
第12步mAuthenticator.addAccount就是pocApp中Authenticator.addAccount
1三、Authenticator.addAccount返回bundle。因爲pocApp沒有實現帳戶登錄,因此後面的流程走步下去了。但咱們看
[-->AbstractAccountAuthenticator.java::Transport:addAccount]發現其內部會調用
response.onResult(bundle);
根據mAuthenticator.addAccount參數可知,response是IAccountAuthenticatorResponse類型就是上面的匿名Session類 。因此這裏執行的是Session.onResult
public void onResult(Bundle result) { if (response != null) { try { ...... response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle returned"); } else { ...... response.onResult(result); } ...... }
1四、由第6步的Session構造函數可知 response就是AmsTask.mResponse,而AmsTask.mResponse = new Response()這裏調用AmsTask內部類Response.onResult
private class Response extends IAccountManagerResponse.Stub { 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); // leave the Future running to wait for the real response to this request } else if (bundle.getBoolean("retry")) { try { doWork(); } catch (RemoteException e) { // this will only happen if the system process is dead, which means // we will be dying ourselves } } else { set(bundle); } }
這裏調用startActivity去啓動帳號登錄activity(launchAnyWhere bug)。源碼分析到此爲止嘞,可是期間涉及到的不少類咱們須要整理下,便於記憶和消化addAccount流程
看到羅,addAccount就是上面這幾個類之間的操做。其實addAccount總結起來也很簡單,accountManager—>accountAuthenticator—>accountAuthenticatorRespone—>accountManagerRespone
參考資料:
一、[深刻理解Android卷二 全文-第八章]深刻理解ContentService和AccountManagerService
二、一步一步教你在 Android 裏建立本身的帳號系統(一)
三、https://github.com/retme7/launchAnyWhere_poc_by_retme_bug_7699048