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-AURI-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);
  1. deliverSelfNotifications返回true
  2. 当我们调用notifyChange的时候,传入了mContentObserver参数。
  3. 最终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)

原创粉丝点击