ContentService源码分析

简单介绍

ContentProvider按照一定规则暴露自己的接口给其它应用来访问自己应用的数据(其实就是自定义增删改查接口并暴露出去,让别的应用访问自己的数据)。当其他应用需要用到该应用的数据时,可以使用ContentResolver,而通过ContentResolver我们可以完成两大功能:
1 通过其对ContentProvider中的数据进行添加、删除、修改和查询操作
2 通过其来监听ContentProvider中数据的变化

那ContentResolver是如何实现这些功能的呢?其实,它内部主要就是调用了ContentService的相应方法,这就说明数据的更新等操作主要由ContentService来完成的。

接下来,我们就结合ContentResolver的使用来分析ContentService

从调用开始分析

在SystemServer的startOtherServices方法中,有这么一段代码

contentService = ContentService.main(context,mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL);
......
......
// 省略部分代码
try {
    if (contentService != null)
        contentService.systemReady();
} catch (Throwable e) {
    reportWtf("making Content Service ready", e);
}

在这里调用ContentService的main方法创建了一个ContentService实例,并调用了它的systemReady()方法。我们分开两步分析:
1. ContentService.main()分析

public static ContentService main(Context context, boolean factoryTest) {
    ContentService service = new ContentService(context, factoryTest);
    ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
    return service;
}

这里主要就是创建了一个ContentService,并将其添加到ServiceManager中。我们进去看下它的构造函数

/*package*/ ContentService(Context context, boolean factoryTest) {
    mContext = context;
    mFactoryTest = factoryTest;
}

这里只是简单的保存了两个变量的引用在本地
2. contentService.systemReady()

public void systemReady() {
    getSyncManager();
}

private SyncManager getSyncManager() {
    if (SystemProperties.getBoolean("config.disable_network", false)) {
        return null;
    }

    synchronized(mSyncManagerLock) {
        try {
            // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
            if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
        } catch (SQLiteException e) {
            Log.e(TAG, "Can't create SyncManager", e);
        }
        return mSyncManager;
    }
}

假如网络被禁止,则不获取SyncManager服务。SyncManager是数据同步的主要类

ContentService的registerContentObserver()方法分析

我们从ContentResolver入手:

/**
 * Register an observer class that gets callbacks when data identified by a
 * given content URI changes.
 *
 * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
 * for a whole class of content.
 * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code>
 * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI
 * specified by <em>uri</em> will cause notifications to be sent. If <code>true</code>, any URI values
 * at or below the specified URI will also trigger a match.
 * @param observer The object that receives callbacks when changes occur.
 * @see #unregisterContentObserver
 */
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
        ContentObserver observer)
{
    registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
}

/** @hide - designated user version */
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
        ContentObserver observer, int userHandle)
{
    try {
        getContentService().registerContentObserver(uri, notifyForDescendents,
                observer.getContentObserver(), userHandle);
    } catch (RemoteException e) {
    }
}

从上边的函数可以看到,ContentResolver的registerContentObserver()方法内部其实是调用了ContentService的registerContentObserver方法,我们进入查看

public void registerContentObserver(Uri uri, boolean notifyForDescendants,
            IContentObserver observer) {
    registerContentObserver(uri, notifyForDescendants, observer,
            UserHandle.getCallingUserId());
}

/**
 * Register a content observer tied to a specific user's view of the provider.
 * @param userHandle the user whose view of the provider is to be observed.  May be
 *     the calling user without requiring any permission, otherwise the caller needs to
 *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and
 *     USER_CURRENT are properly handled; all other pseudousers are forbidden.
 */
@Override
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
        IContentObserver observer, int userHandle) {
    if (observer == null || uri == null) {
        throw new IllegalArgumentException("You must pass a valid uri and observer");
    }

    enforceCrossUserPermission(userHandle,
            "no permission to observe other users' provider view");

    if (userHandle < 0) {
        if (userHandle == UserHandle.USER_CURRENT) {
            userHandle = ActivityManager.getCurrentUser();
        } else if (userHandle != UserHandle.USER_ALL) {
            throw new InvalidParameterException("Bad user handle for registerContentObserver: "
                    + userHandle);
        }
    }

    synchronized (mRootNode) {
        mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
                Binder.getCallingUid(), Binder.getCallingPid(), userHandle);
        if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
                " with notifyForDescendants " + notifyForDescendants);
    }
}

ContentService的registerContentObserver方法内部实现很简单:就是将uri和observer的对应关系保存到mRootNode变量中

ContentService的nitofyChange()分析

我们从ContentResolver入手:

public void notifyChange(Uri uri, ContentObserver observer) {
    notifyChange(uri, observer, true /* sync to network */);
}

public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
    notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId());
}

public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
        int userHandle) {
    try {
        getContentService().notifyChange(
                uri, observer == null ? null : observer.getContentObserver(),
                observer != null && observer.deliverSelfNotifications(), syncToNetwork,
                userHandle);
    } catch (RemoteException e) {
    }
}

从上边的函数可以看到,ContentResolver的notifyChange()方法内部其实是调用了ContentService的notifyChange方法,我们进入查看

try {
    ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
    synchronized (mRootNode) {
        mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
                userHandle, calls);
    }
    final int numCalls = calls.size();
    for (int i=0; i<numCalls; i++) {
        ObserverCall oc = calls.get(i);
        try {
            oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
            }
        } catch (RemoteException ex) {
            synchronized (mRootNode) {
                Log.w(TAG, "Found dead observer, removing");
                IBinder binder = oc.mObserver.asBinder();
                final ArrayList<ObserverNode.ObserverEntry> list
                        = oc.mNode.mObservers;
                int numList = list.size();
                for (int j=0; j<numList; j++) {
                    ObserverNode.ObserverEntry oe = list.get(j);
                    if (oe.observer.asBinder() == binder) {
                        list.remove(j);
                        j--;
                        numList--;
                    }
                }
            }
        }
    }
    if (syncToNetwork) {
        SyncManager syncManager = getSyncManager();
        if (syncManager != null) {
            syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
                    uri.getAuthority());
    }
} finally {
    restoreCallingIdentity(identityToken);
}

上边主要有两大操作:
- 从mRootNode中获取所有匹配的ContentObserver并保存在变量calls中,遍历calls,调用每个ContentObserver的onChange()方法。假如出现异常:”Found dead observer, removing”
- 假如syncToNetwork为true,则调用syncManager.scheduleLocalSync()进行同步

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值