[컴][안드로이드] ContentResolver 의 source code flow

ContentResolver 동작 / How to work ContentResolver



ContentResolver 가 어떻게 ContentProvider 를 이용하는지 살펴보자. 좀 더 포괄적인 글은 See Also 를 참고하자.

Provider 의 등록

provider 는 AndroidManifest.xml 에 등록하게 되어 있다.

<application 
    android:label="@string/app_name"
    android:icon="@drawable/ic_launcher"
    android:theme="@android:style/Theme.NoTitleBar">
 
 <!----->
 ...

    <provider
            android:name="com.namh.utils.provider.ChartDatabaseProvider"
            android:authorities="com.muchart"
            android:exported="false"
            android:grantUriPermissions="true"
            android:label="ChartDatabaseProvider"
            android:readPermission="com.muchart.READ"
            android:writePermission="com.muchart.WRITE" />
    
     
</application>


이 등록한 Provider 를 사용하기 위해서 우리는 ContentResolver 를 사용한다. ContentResolver 내부에서 Provider 를 호출하는 구조이다.

이 ContentProvider 의 query() 를 이용하려고 하면 아래처럼 Resolver 를 통해서 query() 를 호출한다.
context.getContentResolver().query()
아래 stack 과 source 들을 살펴보면, ContentResolver 가 ContentProvider 를 가져와서 그 ContentProvider.query() 를 호출하고 있다.

Stack trace

context.getContentResolver().query()
query():51, ChartDatabaseProvider {com.namh.utils.provider}
query():652, ContentProvider {android.content}
query():189, ContentProvider$Transport {android.content}
query():372, ContentResolver {android.content}
query():315, ContentResolver {android.content}


Source flow

// ContentResolover
IContentProvider unstableProvider = acquireUnstableProvider(uri);
...
qCursor = unstableProvider.query(uri, projection,
                         selection, selectionArgs, sortOrder, remoteCancellationSignal);

// ContentProvider$Transport
enforceReadPermission(uri);
ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
                     CancellationSignal.fromTransport(cancellationSignal));

// MyContetProvider



acquireExistingProvider

그럼 이 ContentResolver 는 어떻게 우리가 등록한 ContentProvider 를 가져올까?acquireUnstableProvider 에서 시작해서 따라가 보면,

에서 ActivityThread.mProviderMap 에 등록해 놓은 Provider 를 찾아서 가져오게 된다. key 는 auth 와 user id 로 결정된다. 자세한 것은 코드를 참고하자.

아마도, AndroidManifest.xml 에 등록하면 app 이 실행될 때 mProviderMap 에 등록되는 듯 하다.(확인 필요)


Stack trace

acquireProvider():4449, ActivityThread {android.app}
acquireUnstableProvider():2002, ContextImpl$ApplicationContentResolver {android.app}
acquireUnstableProvider():1101, ContentResolver {android.content}
query():356, ContentResolver {android.content}


Source flow

// ContentResolver
public final IContentProvider acquireUnstableProvider(Uri uri) {
    if (!SCHEME_CONTENT.equals(uri.getScheme())) {  // uri.getScheme() = "content"

        return null;
    }
    String auth = uri.getAuthority();
    if (auth != null) {
        return acquireUnstableProvider(mContext, uri.getAuthority());
    }
    return null;
}




// ContextImpl$ApplicationContentResolver
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
    return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false);
}

// ActivityThread
public final IContentProvider acquireProvider(...){
 final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); 
 if (provider != null) {
     return provider;
 }
 ...

}

public final IContentProvider acquireExistingProvider(
        Context c, String auth, int userId, boolean stable) {

    synchronized (mProviderMap) {
        final ProviderKey key = new ProviderKey(auth, userId);
        final ProviderClientRecord pr = mProviderMap.get(key);
        if (pr == null) {
            return null;
        }
        ...

        return provider;
    }
}




See Also









댓글 없음:

댓글 쓰기