Android 系统服务之 ContentService
来源:互联网 发布:js 防止sql注入 编辑:程序博客网 时间:2024/06/14 19:58
本文基于AOSP-7.1.1-R9源码分析,源码可以参见 frameworks/base/+/android-7.1.1_r9;
从名字上看,ContentService是内容服务,和ContentProvider以及ContentRelsover相互关联。在使用ContentProvider创建共享的数据之后,其他进程为了访问数据,会调用ContentRelsover来进行相关操作。
在Android系统代码里面,经常会有如下代码所示操作。首先通过ContentResolver注册一个内容观察者,当VIBRATE_WHEN_RINGING_URI对应的Uri发生变化之后,就会回调内容观察者的onChange方法,通知回调的核心类都是ContentService。代码如下:
final ContentResolver cr = getContentResolver(); cr.registerContentObserver(VIBRATE_WHEN_RINGING_URI, false, this);
在Android系统中,可以自己添加不同类型的账号,比如Google、163、微信、QQ,最终在设置下面的账号会列出系统所有的账号,我们可以控制所有的账户都不进行同步,也可以单独控制每个账号知否进行同步。ContentService会响应所有的请求同步操作,而且也会记录所有账户的同步信息。
综上所述,ContentService的主要作用有两个:
- 管理系统内容观察者
- 控制系统同步机制
接下来我们将从以上两个方面对ContentService的框架展开分析,首先从服务启动开始。
启动ContentService
和其他的系统服务一样,ContentService也是在SystemServer里面进行启动。ActivityManagerService启动完成之后,在PHASE_ACTIVITY_MANAGER_READY阶段会启动ContentService服务。在ContentService$LifeCycle的onStart方法里面,会对ContentService进行初始化,等收到onBootPhase之后,会调用systemReady初始化SyncManager.
@ContenteService.java
public static class Lifecycle extends SystemService { private ContentService mService; public Lifecycle(Context context) { super(context); } @Override public void onStart() { final boolean factoryTest = (FactoryTest .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL); mService = new ContentService(getContext(), factoryTest); publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService); } @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mService.systemReady(); } }
内容观察者机制
内容观察者机制就是使用的java的观察者模式。首先通过registerContentObserver注册观察者,等观察者感兴趣的Uri发生变化之后,ContentService会通知观察者进行更新的动作,调用观察者的onChange方法。
注册观察者
如图1-1所示,假设我们现在监听的uri是content://com.android.email.provider/account,当我们执行registerContentObserver之后,会调用到ConentService的registerContentObserver方法。
@ContentService.java
public void registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer, int userHandle) { // ... synchronized (mRootNode) { mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode, uid, pid, userHandle); // ... } }
在registerContentObserver方法里面,会判断当前请求进程的权限和当前的用户,紧接着就会通过mRootNode.addObserverLocked方法,把当前的Uri等信息添加进一个树结构。
首先介绍两个类:
- ObserverNode: 用来存储节点的数据结构。Uri的结构里面除了scheme,每一个部分都是一个节点。对于content://com.android.email.provider/account来说,com.android.email.provider和account是两个子节点
- ObserverEntry: 用来保存完整的Uri对应的观察者的一些信息。
mRootNode是ObserverNode的一个实例,每个节点有两个很重要的成员变量mChildren和mObservers。:
- mChildren: 用来保存所有的子节点。
- mObservers: 用来存储调用registerContentObserver的进程注册的observer对象、以及进程的pid、uid、等信息。后续Uri对应的值发生变化之后回调onChange,正是通过从mObservers里面获取得正确对象。
先做一个简单介绍:
private String mName; private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>(); private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
接下来我们来分析一下,content://com.android.email.provider/account是如何添加进mChildren和mObservers里面去的。
@ContentService.java
private void addObserverLocked(Uri uri, int index, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle) { // If this is the leaf node add the observer if (index == countUriSegments(uri)) { // [a] 添加ObServerEntry mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock, uid, pid, userHandle)); return; } // Look to see if the proper child already exists String segment = getUriSegment(uri, index); if (segment == null) { throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer"); } int N = mChildren.size(); for (int i = 0; i < N; i++) { ObserverNode node = mChildren.get(i); if (node.mName.equals(segment)) { // [b] 添加child node 的ObServer node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, observersLock, uid, pid, userHandle); return; } } // No child found, create one ObserverNode node = new ObserverNode(segment); mChildren.add(node); // [c] 添加当前节点的Observer node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, observersLock, uid, pid, userHandle); }
第一次addObserverLocked,[a] 处,index是0,不相等。[b] getUriSegment返回的是第一个子节点是com.android.email.provider,默认情况下,mChildren里面不存在名字是com.android.email.provider的节点。[c],创建新的ObserverNode,并添加进mChildrens,继续添加后续的节点。
第二次addObserverLocked,[a] 处,index是1,不相等。[b] segment是account,名称是com.android.email.provider节点没有子节点,故直接跳过,重新创建名称是account的子节点,并继续添加后续的节点。
第三次addObserverLocked,[a] 处,index是2,相等。给名称是account的子节点添加一个ObserverEntry对象。
至此添加观察者信息的动作完成。
总结:addObserverNode方法是通过遍历Uri的segments来进行的,每遍历一个segments就会创建一个新的子节点,等所有的segments遍历完成之后,会创建一个记录观察者信息的ObserverEntry信息。
叶子节点才包含观察者。根节点是没有观察者的。
dump 观察者树
用adb shell dumpsys content
方法,可以查看到系统所有的注册信息。
仅仅查看account的观察者树,可以看到系统已经注册的相关信息。
Observer Tree:
com.android.provider/accout: pid=2186 uid10038 user=0 target=3ef76f0
settings/system/alarm_alert: pid=20935 uid=10036 user=0 target=6eb95e9
settings/global: pid=1472 uid=1000 user=0 target=532026e
…
通知观察者Uri发生变化
注册了观察之后,等到我们观察的Uri对应的值发生了变化之后,就需要通知观察者。在ContentProvider的子类里面,通常会调用getContext.getContentRelsover.notifyChange(notifyUri,observer)来触发通知。最终调用ConetentService的notifyChange方法来实现相关的逻辑。
@ContentService.java
@Override public void notifyChange(Uri uri, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int userHandle) { // ... try { ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); synchronized (mRootNode) { // [a] 收集对uri感兴趣的观察者。 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications, flags, userHandle, calls); } final int numCalls = calls.size(); for (int i=0; i<numCalls; i++) { ObserverCall oc = calls.get(i); try { // [b] 调用观察者的onChange方法。 oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
接下来,我们还是以content://com.android.email.provider/account为例子来说明[a]
@ContentService
/** * targetUserHandle is either a hard user handle or is USER_ALL */ public void collectObserversLocked(Uri uri, int index, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ArrayList<ObserverCall> calls) { String segment = null; int segmentCount = countUriSegments(uri); if (index >= segmentCount) { // This is the leaf node, notify all observers if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName); // [c] 收集caller collectMyObserversLocked(true, observer, observerWantsSelfNotifications, flags, targetUserHandle, calls); } else if (index < segmentCount){ segment = getUriSegment(uri, index); if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / " + segment); // Notify any observers at this level who are interested in descendants // [d] 收集对segment对应的父节点observer。 collectMyObserversLocked(false, observer, observerWantsSelfNotifications, flags, targetUserHandle, calls); } int N = mChildren.size(); for (int i = 0; i < N; i++) { ObserverNode node = mChildren.get(i); Log.d(TAG, "collectObserversLocked: " + segment); if (segment == null || node.mName.equals(segment)) { // We found the child, // [e] 收集observer node.collectObserversLocked(uri, index + 1, observer, observerWantsSelfNotifications, flags, targetUserHandle, calls); if (segment != null) { break; } } } }
首先我们看一下collectMyObserversLocked方法:
private void collectMyObserversLocked(boolean leaf, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ArrayList<ObserverCall> calls) { int N = mObservers.size(); IBinder observerBinder = observer == null ? null : observer.asBinder(); for (int i = 0; i < N; i++) { } // ... } }
只有当mObservers的大小大于0的时候,才会进行收集。如前面注册讲到,只有叶子节点才有mObserver对象,对于uri=content://com.android.email.provider/account来说,叶子节点是account,那么最终收集到的observer是account节点的mObserver.逻辑此处不再分析。
registerContentObserver的notifyForDescendants参数
在registerContentObserver方法里面,有一个参数是notifyForDescendants,这个参数具体是什么意思呢?翻译过来就是:notify for descendants,对于descendants的改变,是不是需要notify父类的观察者。
假设
- URI-A:content://com.android.emailprovider/account
- URI-B:content://com.android.emailprovider/account/100
都被加入了监听。系统当前notify的是URI-B:
- notifyForDescendants=true. 同时触发(notify)监听URI-A和URI-B的观察者的onChange方法。
- notifyForDescendants=false. 只会触发(notify)监听 URI-B 的观察者的方法。
所有的实现都是在collectMyObserversLocked
里面。
if (!entry.notifyForDescendants) { continue; } calls.add(new ObserverCall(this, entry.observer, selfChange, UserHandle.getUserId(entry.uid)));
notifyChange的observerWantsSelfNotifications参数
在ContentService#notifyChange里面有一个observerWantsSelfNotifications的参数。表示什么意思呢?
假设在observer A里面注册了监听,当getContext().getContentResolver().notifyChange
满足如下三个条件的时候。
- observer不是null
- observer.deliverSelfNotifications() return ture.
那么observerWantsSelfNotifications=true,最终在observerA的onChange方法里面调用onChange的时候,selfChange的值是true.
下面举例说明:
mContentObserver = new ContentObserver(new Handler()) { @Override public boolean deliverSelfNotifications() { return true; } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); } @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); } };
getContentResolver().notifyChange(Settings.System.DEFAULT_RINGTONE_URI, mContentObserver);
- deliverSelfNotifications返回true
- 当我们调用notifyChange的时候,传入了mContentObserver参数。
- 最终onChange的selfChange参数是true。
同步机制
frameworks/base/services/core/java/com/android/server/content/SyncOperation.java
frameworks/base/services/core/java/com/android/server/content/SyncJobService.java
frameworks/base/services/core/java/com/android/server/content/SyncStorageEngine.java
frameworks/base/services/core/java/com/android/server/content/ContentService.java
frameworks/base/services/core/java/com/android/server/content/SyncManager.java
frameworks/base/services/core/java/com/android/server/content/SyncOperation.java
ContentService除了控制注册以及监控Uri的变化之外,还有一个很重要的功能就是控制系统的同步框架机制。在notifyChange里面还有一个重要的flags,ContentResolver.NOTIFY_SYNC_TO_NETWORK
,表示当前的更改是否需要同步到网络。
@ContentService.java
@Override public void notifyChange(Uri uri, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int userHandle) { if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid, uri.getAuthority()); } } }
Android系统创建了数据同步的框架,android 开发者网站介绍了自定义sync-adapter的步骤,其中数据同步的地方是复写AbstractThreadedSyncAdapter的public abstract void onPerformSync(Account account, Bundle extras,
方法。解下来我们来分析一下,系统框架是如何启动
String authority, ContentProviderClient provider, SyncResult syncResult);onPerformSync
的。
同步来源
根据用户不同的操作和系统不同的同步周期,将请求同步的来源分成5种:
- SOURCE_SERVER 在设置账户界面,进入到具体的账户,然后点击同步。账户第一次添加的时候,设置成了自动同步。比如我们在登录Email账户的过程中,设置了自动同步的功能。那么就会产生一个来源是SERVER的同步操作。
- SOURCE_LOCAL 同步本地内容到服务器
- SOURCE_POLL 没有具体的authority,没有针对具体的账户。比如打开和关闭系统同步的总开关。
- SOURCE_USER 用户手动点击同步。
- SOURCE_PERIODIC 周期性同步。比如Email同步设置的时间为每15分钟同步一次。
同步本地内容到网络
简单上一张流程图:
接着ContentService#notifiChange方法里面的syncManager.scheduleLocalSync方法。
@ContentService
public void scheduleLocalSync(Account account, int userId, int reason, String authority) { final Bundle extras = new Bundle(); extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true); scheduleSync(account, userId, reason, authority, extras, AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY); }
请求一个同步计划。包含当前的账户以及请求的reason。
在scheduleSync
里面经过一系列的判断:
1. 首先根据出入的account和user,创建一个AccountUser对象。
2. 根据extra信息来获取当前的同步信息,比如是否是上传、人工同步、是否需要设置BackOff时间、还会获取当前的来源。
3. 根据当前的account和autority信息,获取系统里面可以进行同步的account信息。
4. 创建一个包含了当前可同步账户相关信息的SyncOperation,然后执行postScheduleSyncMessage请求计划同步操作。
最终会调用postScheduleSyncMessage
。
@SyncManager.java
postScheduleSyncMessage( new SyncOperation(account.account, account.userId, owningUid, owningPackage, reason, source, authority, newExtras, allowParallelSyncs), minDelayMillis );
紧接着通过Handler的方式,发送MESSAGE_SCHEDULE_SYNC的消息。从而执行scheduleSyncOperationH。
@SyncManager.java
#scheduleSyncOperationH
private void scheduleSyncOperationH(SyncOperation syncOperation, long minDelay) { final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (syncOperation == null) { Slog.e(TAG, "Can't schedule null sync operation."); return; } if (!syncOperation.ignoreBackoff()) { Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target); if (backoff == null) { Slog.e(TAG, "Couldn't find backoff values for " + syncOperation.target); backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE); } long now = SystemClock.elapsedRealtime(); long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0 : backoff.first - now; long delayUntil = mSyncStorageEngine.getDelayUntilTime(syncOperation.target); long delayUntilDelay = delayUntil > now ? delayUntil - now : 0; if (isLoggable) { Slog.v(TAG, "backoff delay:" + backoffDelay + " delayUntil delay:" + delayUntilDelay); } minDelay = Math.max(minDelay, Math.max(backoffDelay, delayUntilDelay)); } // ...}
BackOff
BackOff,从字面意思理解比较困难。查了相关资料,有一个翻译是:Back off(退避):发生冲突时的强制性重传延迟。和这个SyncManager里面的意义比较相似。对于同步来说,backoff表示:同步失败之后,延时进行同步。
同步失败之后,会调用increaseBackoffSetting来增加Backoff 时间。如果先前已经设置了backoff 延时,那么就会是以前同步时间的两倍。紧接着会对当前的延时进行判断,不能超过最大的延时DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS,默认是1个小时。也就是说一次同步操作失败之后,如果条件没有发生改变,至少在一个小时只能回进行下一次的同步。
继续回到scheduleSyncOperationH流程,有两个delay时间:
- backoffDelay时间:上次同步失败会设置一个delay的时间。
- delayUntilDelay 时间:是具体的同步Adapter在系统的onPerformSync里面进行同步数据传输的时候设置,一般情况下为0。
取出以上两个delay时间里面的最大值。接下来
#scheduleSyncOperationH
// ... if (!syncOperation.isPeriodic) { // Check currently running syncs for (ActiveSyncContext asc: mActiveSyncContexts) { if (asc.mSyncOperation.key.equals(syncOperation.key)) { if (isLoggable) { Log.v(TAG, "Duplicate sync is already running. Not scheduling " + syncOperation); } return; } } int duplicatesCount = 0; long now = SystemClock.elapsedRealtime(); syncOperation.expectedRuntime = now + minDelay; List<SyncOperation> pending = getAllPendingSyncs(); SyncOperation opWithLeastExpectedRuntime = syncOperation; for (SyncOperation op : pending) { if (op.isPeriodic) { continue; } if (op.key.equals(syncOperation.key)) { if (opWithLeastExpectedRuntime.expectedRuntime > op.expectedRuntime) { opWithLeastExpectedRuntime = op; } duplicatesCount++; } } if (duplicatesCount > 1) { Slog.e(TAG, "FATAL ERROR! File a bug if you see this."); } for (SyncOperation op : pending) { if (op.isPeriodic) { continue; } if (op.key.equals(syncOperation.key)) { if (op != opWithLeastExpectedRuntime) { if (isLoggable) { Slog.v(TAG, "Cancelling duplicate sync " + op); } getJobScheduler().cancel(op.jobId); } } } if (opWithLeastExpectedRuntime != syncOperation) { // Don't schedule because a duplicate sync with earlier expected runtime exists. if (isLoggable) { Slog.v(TAG, "Not scheduling because a duplicate exists."); } return; } } // ...
如果是非周期性的同步,如果存在重复的操作,那么只保留离当前时间最近的op。
JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId, new ComponentName(mContext, SyncJobService.class)) .setExtras(syncOperation.toJobInfoExtras()) .setRequiredNetworkType(networkType) .setPersisted(true) .setPriority(priority); if (syncOperation.isPeriodic) { b.setPeriodic(syncOperation.periodMillis, syncOperation.flexMillis); } else { if (minDelay > 0) { b.setMinimumLatency(minDelay); } getSyncStorageEngine().markPending(syncOperation.target, true); } if (syncOperation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)) { b.setRequiresCharging(true); } getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage, syncOperation.target.userId, syncOperation.wakeLockName());
紧接着会根据当前的syncOperation创建JobInfo信息,然后调用JobScheduler设置schedule.
接下来的逻辑涉及到JobScheduler,不是本文讲解重点。后续会有专门的文章来进行讲解。
SyncJobService
在SyncManager初始化的过程中,会初始化SyncJobService。主要是为了使用jobschedule机制,用来实现自己的JobSchedule服务。
final Intent startServiceIntent = new Intent(mContext, SyncJobService.class); startServiceIntent.putExtra(SyncJobService.EXTRA_MESSENGER, new Messenger(mSyncHandler)); new Handler(mContext.getMainLooper()).post(new Runnable() { @Override public void run() { mContext.startService(startServiceIntent); } });
根据JobSchedule的机制,最终会调用SyncJobService#onStartJob方法。
@Override public boolean onStartJob(JobParameters params) { boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); synchronized (jobParamsMap) { jobParamsMap.put(params.getJobId(), params); } Message m = Message.obtain(); m.what = SyncManager.SyncHandler.MESSAGE_START_SYNC; SyncOperation op = SyncOperation.maybeCreateFromJobExtras(params.getExtras()); if (op == null) { Slog.e(TAG, "Got invalid job " + params.getJobId()); return false; } if (isLoggable) { Slog.v(TAG, "Got start job message " + op.target); } m.obj = op; sendMessage(m); return true; }
接下来,会发送消息。
private void startSyncH(SyncOperation op) { final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (isLoggable) Slog.v(TAG, op.toString()); if (mStorageIsLow) { deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE); return; } if (op.isPeriodic) { // Don't allow this periodic to run if a previous instance failed and is currently // scheduled according to some backoff criteria. List<SyncOperation> ops = getAllPendingSyncs(); for (SyncOperation syncOperation: ops) { if (syncOperation.sourcePeriodicId == op.jobId) { mSyncJobService.callJobFinished(op.jobId, false); return; } } // Don't allow this periodic to run if a previous instance failed and is currently // executing according to some backoff criteria. for (ActiveSyncContext asc: mActiveSyncContexts) { if (asc.mSyncOperation.sourcePeriodicId == op.jobId) { mSyncJobService.callJobFinished(op.jobId, false); return; } } // Check for adapter delays. if (isAdapterDelayed(op.target)) { deferSyncH(op, 0 /* No minimum delay */); return; } } // Check for conflicting syncs. for (ActiveSyncContext asc: mActiveSyncContexts) { if (asc.mSyncOperation.isConflict(op)) { // If the provided SyncOperation conflicts with a running one, the lower // priority sync is pre-empted. if (asc.mSyncOperation.findPriority() >= op.findPriority()) { if (isLoggable) { Slog.v(TAG, "Rescheduling sync due to conflict " + op.toString()); } deferSyncH(op, SYNC_DELAY_ON_CONFLICT); return; } else { if (isLoggable) { Slog.v(TAG, "Pushing back running sync due to a higher priority sync"); } deferActiveSyncH(asc); break; } } } final int syncOpState = computeSyncOpState(op); switch (syncOpState) { case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: case SYNC_OP_STATE_INVALID: { mSyncJobService.callJobFinished(op.jobId, false); } return; } if (!dispatchSyncOperation(op)) { mSyncJobService.callJobFinished(op.jobId, false); } setAuthorityPendingState(op.target); }
经过一系列的判断,会执行dispatchSyncOperation方法。当周期性同步失败之后,系统会把syncOperation的sourcePeriodicId设置成op.jobId,所以如果syncOperation.sourcePeriodicId == op.jobId,说明syncOperation失败过。
- 如果是周期性的op,先前发生过失败(syncOperation.sourcePeriodicId == op.jobId),且有pending和activite的job正在执行,则调用callJobFinished方法结束当前的job。当周期性的同步发生失败之后,我们会创建一个一次性(one-off sync)的同步,所以以前的job不需要了,需要执行finish动作。
- 如果op都是正常的流程,则调用dispatchSyncOperation分发当前的同步操作。
@SyncManager
private boolean dispatchSyncOperation(SyncOperation op) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op); Slog.v(TAG, "num active syncs: " + mActiveSyncContexts.size()); for (ActiveSyncContext syncContext : mActiveSyncContexts) { Slog.v(TAG, syncContext.toString()); } } // Connect to the sync adapter. int targetUid; ComponentName targetComponent; final SyncStorageEngine.EndPoint info = op.target; SyncAdapterType syncAdapterType = SyncAdapterType.newKey(info.provider, info.account.type); final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo; syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId); if (syncAdapterInfo == null) { Log.d(TAG, "can't find a sync adapter for " + syncAdapterType + ", removing settings for it"); mSyncStorageEngine.removeAuthority(info); return false; } targetUid = syncAdapterInfo.uid; targetComponent = syncAdapterInfo.componentName; ActiveSyncContext activeSyncContext = new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid); if (Log.isLoggable(TAG, Log.VERBOSE)) { Slog.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext); } activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext); mActiveSyncContexts.add(activeSyncContext); // Post message to begin monitoring this sync's progress. postMonitorSyncProgressMessage(activeSyncContext); // [a] bind to sync adapter if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) { Slog.e(TAG, "Bind attempt failed - target: " + targetComponent); closeActiveSyncContext(activeSyncContext); return false; }
[a] 处,根据op里面的信息,获取当前的account和syncadapter,然后请求bindToSyncAdapter。
@SyncManager
boolean bindToSyncAdapter(ComponentName serviceComponent, int userId) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this); } Intent intent = new Intent(); intent.setAction("android.content.SyncAdapter"); intent.setComponent(serviceComponent); intent.putExtra(Intent.EXTRA_CLIENT_LABEL, com.android.internal.R.string.sync_binding_label); intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser( mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, new UserHandle(userId))); mBound = true; // [a] bindService final boolean bindResult = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mSyncOperation.target.userId)); // ... }
[a] 处,根据Adapter对应的组件信息,启动对应的服务(AuthenticatorService的子类),当服务启动成功之后,调用onServiceConnected方法。
public void onServiceConnected(ComponentName name, IBinder service) { Message msg = mSyncHandler.obtainMessage(); msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED; msg.obj = new ServiceConnectionData(this, service); mSyncHandler.sendMessage(msg); }
发送MESSAGE_SERVICE_CONNECTED的消息。
case SyncHandler.MESSAGE_SERVICE_CONNECTED: { ServiceConnectionData msgData = (ServiceConnectionData) msg.obj; if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: " + msgData.activeSyncContext); } // Check that this isn't an old message. if (isSyncStillActiveH(msgData.activeSyncContext)) { runBoundToAdapterH( msgData.activeSyncContext, msgData.adapter); }
接下来请求Adapter进行同步的操作。
private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext, IBinder syncAdapter) { final SyncOperation syncOperation = activeSyncContext.mSyncOperation; try { activeSyncContext.mIsLinkedToDeath = true; syncAdapter.linkToDeath(activeSyncContext, 0); activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter); activeSyncContext.mSyncAdapter .startSync(activeSyncContext, syncOperation.target.provider, syncOperation.target.account, syncOperation.extras); } catch (RemoteException remoteExc) { Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc); closeActiveSyncContext(activeSyncContext); increaseBackoffSetting(syncOperation.target); scheduleSyncOperationH(syncOperation); } catch (RuntimeException exc) { closeActiveSyncContext(activeSyncContext); Slog.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc); } }
在runBoundToAdapterH中,通过asInterface获取ISyncAdapterImpl,然后调用,然后请求startSync
同步.
接下来
@AbstractThreadedSyncAdapter
public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) { // ... SyncThread syncThread = new SyncThread( "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), syncContextClient, authority, account, extras); mSyncThreads.put(threadsKey, syncThread); syncThread.start(); alreadyInProgress = false; } else { alreadyInProgress = true; } }
启动SyncThread的开始进行同步操作。就会调用SyncThread的run方法。
private class SyncThread extends Thread { // ... @Override public void run() { // ... AbstractThreadedSyncAdapter.this.onPerformSync(mAccount, mExtras, mAuthority, provider, syncResult);
至此,就调用了onPerformSync,后面不同的同步Adapter对应自己的实现处理。
SyncStorageEngine
系统所有的同步操作记录以及历史记录等信息是通过SyncStorageEngine来管理
我们可以使用adb shell dumpsys content
打印以上所有存储的信息。
StorageEngine的初始化过程中。首先会在/data/system/sync下面创建三个文件:
- accounts.xml 存储账号的信息。比如我们登录了任意的账号
- status.bin 存储的是当前的同步状态信息,比如对应账号是否支持同步、请求方式同级等,用SyncStatusInfo来控制。
Sync Status
Account 938603063@qq.com u0 com.android.email
// =======================================================================
Authority Syncable Enabled Delay Loc Poll Per Serv User Tot Time Last Sync
———————————————————————————————————————-
com.android.email.provider 1 true 1287 5 7 11 24 3666 21:06:33 LOCAL SUCCESS
2017-07-17 09:15:07
PERIODIC FAILURE
2017-07-17 09:15:22
io-error
- stats.bin 存储过去4周同步成功以及失败的信息。
Sync Statistics
Today: Success (36 for 68.5s avg=1.9s) Failure (38 for 1591.4s avg=41.8s)
Day-1: Success (162 for 1.4s avg=0.0s) Failure (330 for 15816.6s avg=47.9s)
Day-2: Success (297 for 2.7s avg=0.0s) Failure (534 for 25963.1s avg=48.6s)
Day-3: Success (230 for 37.3s avg=0.1s) Failure (363 for 15845.5s avg=43.6s)
Day-4: Success (244 for 185.6s avg=0.7s) Failure (348 for 3667.9s avg=10.5s)
Day-5: Success (237 for 2.3s avg=0.0s) Failure (443 for 4677.4s avg=10.5s)
Day-6: Success (46 for 3.0s avg=0.0s) Failure (82 for 984.3s avg=12.0s)
Week-1: Success (28 for 128.1s avg=4.5s) Failure (34 for 344.1s avg=10.1s)
- Android 系统服务之 ContentService
- Android System Server大纲之ContentService和ContentProvider原理剖析
- Android之系统服务-WindowManager
- Android之getSystemService 各种系统服务总结
- Android系统服务之看门狗(WatchDog)
- Androidの系统服务之getSystemService
- android系统裁减之服务裁减
- Android系统服务之WindowManager整理
- Android系统服务之LightsService实现架构
- Android提供的系统服务之--AlarmManager(闹钟服务)
- Android提供的系统服务之--AlarmManager(闹钟服务)
- Android提供的系统服务之--PowerManager(电源服务)
- Android提供的系统服务之--WindowManager(窗口管理服务)
- Android提供的系统服务之--LayoutInflater(布局服务)
- Android系统服务分析之服务注册过程
- android系统原理二之系统服务等初始化
- 定制Android系统开发之二——系统服务
- 定制Android系统开发之二——系统服务
- [51nod1773][A国的贸易][fwt]解题报告
- Activity的几个主要函数
- 随你而舞
- 解决Error:java: 无效的源发行版: 1.8
- Lua CJSON安装和使用
- Android 系统服务之 ContentService
- 6.0权限问题
- jsp多行注释,java注释
- tensorflow_Faster rcnn问题解决
- JDBC 数据库连接池 小结
- 为ViewPager添加视图切换动画
- 怎样才可以修改cad线型
- Linux:进程、进程组、会话、作业、控制终端的概念
- Android Matrix