2012/03/17

Android:Contextを生成しているモジュールは?

getContentResolverの戻り値を決定している箇所を特定するために、Contextの実体につ
いて調査しました。

getContentResolverはContextクラスで定義された抽象メソッドです。
public abstract ContentResolver getContentResolver();

これを実装した具象クラスを探ります。

getContentResolverを呼び出すActivityクラスの型階層は下記です。



Activityとその親クラスであるContextThemeWrapperはgetContentResolverを実装していません。
さらに親クラスのContextWrapperを見ると、その実装があります。

@Override
public ContentResolver getContentResolver() {
    return mBase.getContentResolver();
}

mBaseのgetContentResolverを呼び出しています(mBaseはContext型)。
続いてmBaseの実体を追います。

mBaseはContextWrapper.attachBaseContextでアタッチされています。
protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}

アタッチされるまでのスタックトレースは下記になります。
ContextWrapper.attachBaseContext(Context)
ContextThemeWrapper.attachBaseContext(Context)
Activity.attach(Context, ActivityThread, Instrumentation, , ,...)
ActivityThread.performLaunchActivity(ActivityThread$ActivityClientRecord, Intent)

attachBaseContextに渡されるContextオブジェクトのbaseは、ActivityThreadクラスの
performLaunchActivityメソッドで作られるContextImplオブジェクトであることがわかります。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// ...
    ContextImpl appContext = new ContextImpl();
    appContext.init(r.packageInfo, r.token, this);
    appContext.setOuterContext(activity);

    activity.attach(appContext, this, getInstrumentation(), r.token,
        r.ident, app, r.intent, r.activityInfo, title, r.parent,
        r.embeddedID, r.lastNonConfigurationInstances, config);
// ...
}

ContextImplを見ると、getContentResolverの実装があります。
アプリでよく使うgetContentResolverではこのメソッドが最終的に呼ばれます。
@Override
public ContentResolver getContentResolver() {
    return mContentResolver;
}

ContextImplクラスを含めた型階層は下記です。


ついでに、mContentResolverの実体はContextImplの内部クラスとして定義されている
ApplicationContentResolverです。
private static final class ApplicationContentResolver extends ContentResolver {
    public ApplicationContentResolver(Context context, ActivityThread mainThread) {
        super(context);
        mMainThread = mainThread;
    }

    @Override
    protected IContentProvider acquireProvider(Context context, String name) {
        return mMainThread.acquireProvider(context, name);
    }

    @Override
    protected IContentProvider acquireExistingProvider(Context context, String name) {
        return mMainThread.acquireExistingProvider(context, name);
    }

    @Override
    public boolean releaseProvider(IContentProvider provider) {
        return mMainThread.releaseProvider(provider);
    }

    private final ActivityThread mMainThread;
}

以上です。