Context解析之Application实例化

以前了解Android的多语言实现很简单,可以在不同的语言环境下使用不同的资源,就做好相应的语言适配就好,但是一直没有实际使用过。
最近公司的项目要用到多国语言切换,并且还是和手机上系统设置里面的语言切换功能一样,于是就上网查了下资料。一般都是在应用类实现多国语言切换,这个是很简单。而我想切换整个系统的语言。由于谷歌没有把系统设置里面的接口给开放出来,所以就只好去查看它的源码了~

Interface to global information about an application environment. This
is an abstract class whose implementation is provided by the Android
system. It allows access to application-specific resources and classes,
as well as up-calls for application-level operations such as launching
activities, broadcasting and receiving intents, etc.

之前在Mac环境下搭建了Android源码,接下来会在简书记录阅读一些经典场景的源码过程,
本文主要是在阅读启动Activity源码过程中做的一些记录,
其中主要的思路是参考罗老师的文章:Android应用程序启动过程源代码分析

android语言切换是在:

Android中最常见的非Context莫属,可以通过它获取资源、获取当前运行的APP相关信息,也可以通过它读取缓存目、启动其它组件,也是很多基本控件的必须。下面,让我们来探秘下Context吧~

几个重要概念

在看Activity启动源码之前,先看几个概念,
这几个是理解Activity启动流程的重要概念:

ActivityManagerService: AMS,服务端的类, 管理着Activity相关的行为

ApplicationThread:实现了IApplicationThread接口,这个接口的说明是

/**
This is given to the activity manager by an application  when it starts up, for the activity manager to tell the application about things it needs to do
**/

它是用来实现ActivityManagerService和ActivityThread之间的交互

ActivityThread:

/**
 * This manages the execution of the main thread in an
 * application process, scheduling and executing activities,
 * broadcasts, and other operations on it as the activity
 * manager requests.
 */

ActivityThread是App主线程(UI线程)管理者,并且作为调度和执行Activity,
broadcast的角色。所以,Activity相关的操作,都是由ActivityThread来调度的。

澳门新葡萄京官网注册 ,对于每一个应用程序来说,都有一个ActivityThread来表示应用程序的主进程,而每一个ActivityThread都包含有一个ApplicationThread实例,它是一个Binder对象,负责和其它进程进行通信。

  • instrumentation
    这里的mInstrumentation是ActivityThread类的成员变量,它的类型是Intrumentation,定义在frameworks/base/core/java/android/app/Instrumentation.java文件中,它用来监控应用程序和系统的交互。
packages/apps/Settings/com/android/settings/LocalePicker.java

1. Context的继承结构

平时我们在使用Context时,是直接使用的已经实例化好的对象,那么具体的Context实例是如何生成的呢?

查看Context
API文档,有以下几个方法可以创建Context实例:

/**
* 根据包名创建Context
*/
public abstract Context createPackageContext(String packageName,
            @CreatePackageOptions int flags) throws PackageManager.NameNotFoundException;

/**
* 根据报名给指定的用户创建Context
*/
public abstract Context createPackageContextAsUser(
            String packageName, int flags, UserHandle user)
            throws PackageManager.NameNotFoundException;

public abstract Context createApplicationContext(ApplicationInfo application,
            int flags) throws PackageManager.NameNotFoundException;

public abstract Context createConfigurationContext(
            @NonNull Configuration overrideConfiguration);          

public abstract Context createDisplayContext(@NonNull Display display);

public abstract Context createDeviceProtectedStorageContext();

public abstract Context createCredentialProtectedStorageContext();

见名知意,各方法为不同的场景服务,此处Context类为abstract,那么具体是如何实现呢?Context直接继承的子类有ContextWrapperMockContext,非直接继承的子类包括常见的Activity,Application,Service等。MockContext为测试时使用,暂且不看,那么上面这几个方法的实现有可能会在ContextWrapper类中。

java.lang.Object
↳ android.content.Context

让我们继续往下查看ContextWrapper
API文档,原来ContextWrapper类只是一个代理,它自己并没有任何实际的逻辑:

Proxying implementation of Context that simply delegates all of its
calls to another Context. Can be subclassed to modify behavior without
changing the original Context.

java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper

翻看源码,查看createPackageContext方法的实现,它并没有对createPackageContext方法做实现,而是交给了mBase:

Context mBase;

public ContextWrapper(Context base) {
    mBase = base;
}

@Override
public Context createPackageContext(String packageName, int flags)
        throws PackageManager.NameNotFoundException {
    return mBase.createPackageContext(packageName, flags);
}

继续查看ContextWrapper子类:

澳门新葡萄京官网注册 1

此处输入图片的描述

直接的子类包括:Application,ContextThemeWrapper,Service,其余的可暂时忽略。可以看到Application和Service是直接继承ContextWrapper的。查看Application源码,并没有对createContext的实现。

Application中对Context赋值只有两个地方:

    /**
     * @hide
     */
    /* package */ 
    final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

    //******************************************************************
    //基类ContextWrapper中给Context赋值
    public ContextWrapper(Context base) {
        mBase = base;
    }

    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

那么这两个方法是在什么地方调用到的呢?说到这里就需要了解APP启动过程。简单来说,当新启动一个Activity时,AMS发现这个Activity所在的APP没有对应的进程信息,会启动一个新的进程,然后进行一系列相关的操作。

源码

说完几个基础概念,下面我们来看startActivity(Intent)的源码:

  1. startActivity函数也是调用了startActivityResult,
    然后跟进去可以看到如下代码:

Instrumentation.ActivityResult ar =
           mInstrumentation.execStartActivity(
               this, mMainThread.getApplicationThread(), mToken, this,
               intent, requestCode, options);

这里就出现了我们上面提到的Instrumentation对象,它是监控应用程序和系统交互的类。执行execStartActivity方法,这里有两个参数重点看一下:
mMainThread.getApplicationThread():
ApplicationThread对象,它是用来与服务端ActivityManagerServer交互的;
mToken: IBinder对象;

  1. 下面是execStartActivity的源代码:

public ActivityResult execStartActivity(
       Context who, IBinder contextThread, IBinder token, Activity target,
       Intent intent, int requestCode, Bundle options) {
   IApplicationThread whoThread = (IApplicationThread) contextThread;
   ...
   try {
       intent.migrateExtraStreamToClipData();
       intent.prepareToLeaveProcess();
       int result = ActivityManagerNative.getDefault()
           .startActivity(whoThread, who.getBasePackageName(), intent,
                 intent.resolveTypeIfNeeded(who.getContentResolver()),
                   token, target != null ? target.mEmbeddedID : null,
                   requestCode, 0, null, options);
       checkStartActivityResult(result, intent);
   } catch (RemoteException e) {
       throw new RuntimeException("Failure from system", e);
   }
   return null;
}

这里我省略了中间一段,就看核心的ActivityManagerNative.getDefault().startActivity这个函数,先看看getDefault获取了一个什么对象

  1. 下面是getDefault的实现:

/*** Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
   return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        //通过ServiceManager获取对应Service
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

上述代码我们看到一段熟悉的Binder机制代码,
就是ServiceManager.getService(“activity”),
大概理解Binder机制就会知道,Binder是C/S架构,而Client客户端就是通过ServiceManager.getService的方式获取服务端代理对象(所以说是代理对象,因为真正的服务端在另外一个进程中)。

  1. 再回到刚刚ActivityManagerNative.getDefault().startActivity,getDefault是IActivityManager接口,
    实例对象是ActivityManagerProxy,下面看看这个ActivityManagerProxy代码:
    这里就是经典的Binder的模式,
    这里的mRemote就是上面第3步代码中获取的Service对象

  2. 第4步通过Binder机制(后面会再详细看看Binder机制,
    简单说就是客户端方法映射到服务端的方法),所以这里就进入了服务端(另外一个进程)ActivityManagerService的startActivity函数:

这里主要是调用了ActivityStackSupervisor类的startActivityMayWait方法,
下面会重点看一下ActivityStackSupervisor这个类的处理:

  1. startActivityMayWait(),
    里面主要是对Intent做了解析,将要启动的Activity的信息保存在ActivityInfo(变量对应的是aInfo)中,
    然后调用startActivityLocked方法;

  2. startActivityLocked:
    这里又解析了一些信息,例如调用者callApp等,然后生成一个ActivityRecord对象

ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, this, container, options);
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);
  1. startActivityUncheckedLocked:
    这个函数大约有六百多行代码,这个函数主要处理了Task相关的逻辑,
    在AndroidManifest或者代码中, 我们可以定义Activity的4中启动模式:
    standard, singleTop, singleTask,
    singleInstance。这里就是判断了具体的启动模式,并根据当前Activity栈的情况,作出不同的处理。
    最终,走到一个基本的启动模式函数:targetStack.startActivityLocked(r,
    newTask, doResume, keepCurTransition, options)
  2. startActivityLocked在ActivityStack文件中,这里继续对Task相关的逻辑做处理,不做深入的分析了,
    直接看接下来的处理: resumeTopActivitiesLocked
  3. resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options);
    它的其中一个参数prev是在stack中的上一个activity,
    那么这个函数要做的是对上一个activity做一些事情了,下面看具体的代码:

// We need to start pausing the current activity so the top one
        // can be resumed...
        boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }

其中的注释说的很明白: 要启动top activity,
我们必须将目前正在运行的activity置于pause的状态。

  1. 下面又来到一个比较关键的节点:“将当前activity置于pause状态”,
    代码如下:

if (prev.app != null && prev.app.thread != null) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
            try {
                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                        prev.userId, System.identityHashCode(prev),
                        prev.shortComponentName);
                mService.updateUsageStats(prev, false);
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            } 

可以看到,最核心的是调用了prev.app.thread.schedulePauseActivity,
其中app是ProcessRecord对象,是当前正在前台运行的应用相关信息;
thread是IApplicationThread对象,文中一开始的时候提到的ApplicationThread实现了这个接口,是应用进程和ActivityManagerService服务进程间通信的桥梁。
下面要执行的就是进程间的通信了,这里是第二次执行Binder进程间通信了(第一次是第5步的时候,
应用进程作为客户端client,通知服务端AMS调用startActivity),这一次,则正好相反,是AMS进程通知应用进程执行pause
activity操作。
————一条分割线————-
这里再详细看看为什么thread.schedulePauseActivity可以完成一次Binder跨进程的调用,在一开始接触Binder的时候,都是client调用service的方法,
而service由ServiceManager对象管理,所以,client要调用service的时候,可以通过ServiceManager.getService(“activity”)这样的方法获取,现在是service调用client,那么service又是怎么知道我要调用哪个client呢?
那要看看thread这个对象是怎么生成的?
通过一层层函数调用发现thread对象传递的流程如下:
最开始,
当application启动的时候,ActivityThread的main函数作为应用程序的入口,
有如下这段代码:

thread.attach(false);
private void attach(boolean system) {
...
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
            }
...
}

这里就通过Binder机制,将mAppThread对象,也就是我们一直提到ApplicationThread传递给ActivityManagerService,
而在service中的处理:

public void handleMessage(Message msg) {
    switch (msg.what) {
        case ATTACH_APPLICATION_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IApplicationThread app = ApplicationThreadNative.asInterface(
                    data.readStrongBinder());
            if (app != null) {
                attachApplication(app);
            }
            reply.writeNoException();
            return true;
        }
    }
}
Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
    app.makeActive(thread, mProcessStats);
}
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
    thread = _thread;
}

上面这段代码, 很好的解释了, 我们上面看到的prev.app.thread对象,
就是当应用启动的时候从ActivityThread传递过来的ApplicationThread对象。所以调了thread.schedulePauseActivity,
就可以实现service与当前应用进程的通信;
————又是一条分割线————-

  1. 这里,我们又回到了应用进程,
    执行的是ApplicationThread对象的schedulePauseActivity方法:

public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport) {
            sendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
                    configChanges);
        }

因为ApplicationThread是ActivityThread的内部类,sendMessage函数是ActivityThread的实现,
如下:

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

可以看到,这里是一个Handler发送消息的机制,ActivityThread的成员变量mH处理了来自ApplicationThread的PAUSEACTIVITY消息。至于这里为什么要用Handler机制呢?因为ApplicationThread作为和服务端交互的桥梁,它是单独挂起一个线程在接收服务端的消息的,
而下面我们要操作的是在主线程(UI线程)做PAUSEACTIVITY的处理,
所以这里就需要一个Handler把消息传递给主线程去执行相应操作。看下面的代码:

//handler处理pause消息
case PAUSE_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
                            (msg.arg1&2) != 0);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
//ActivityThread处理pauseActivity
private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
            if (userLeaving) {
                performUserLeavingActivity(r);
            }

            r.activity.mConfigChangeFlags |= configChanges;
            performPauseActivity(token, finished, r.isPreHoneycomb());

            // Make sure any pending writes are now committed.
            if (r.isPreHoneycomb()) {
                QueuedWork.waitToFinish();
            }

            // Tell the activity manager we have paused.
            if (!dontReport) {
                try {
                 //通知服务端
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {
                }
            }
            mSomeActivitiesChanged = true;
        }
    }
//由activity管理者来执行pause操作
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState) {
            mInstrumentation.callActivityOnPause(r.activity);
            }
//Activity 文件中的pause处理
final void performPause() {
        mDoReportFullyDrawn = false;
        mFragments.dispatchPause();
        mCalled = false;
        onPause();
        mResumed = false;
        if (!mCalled && getApplicationInfo().targetSdkVersion
                >= android.os.Build.VERSION_CODES.GINGERBREAD) {
            throw new SuperNotCalledException(
                    "Activity " + mComponent.toShortString() +
                    " did not call through to super.onPause()");
        }
        mResumed = false;
    }

可以看到,在最后Activity中的performPause()
函数中,调用了我们熟悉的生命周期函数onPause(),
到这里,就完成了服务端的PAUSEACTIVITY操作,
然后再ActivityThread中,又通知了服务端完成pauseActivity操作:
ActivityManagerNative.getDefault().activityPaused(token);

  1. 下面又通过Binder机制回到Service端的代码,
    ActivityManagerService的activityPaused():

Override
    public final void activityPaused(IBinder token) {
        final long origId = Binder.clearCallingIdentity();
        synchronized(this) {
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                stack.activityPausedLocked(token, false);
            }
        }
        Binder.restoreCallingIdentity(origId);
    }
//ActivityStack.java
final void activityPausedLocked(IBinder token, boolean timeout) {
    final ActivityRecord r = isInStackLocked(token);
    if (r != null) {
        mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
        if (mPausingActivity == r) {
            completePauseLocked(true);
        } 
    }
}

接下来继续执行resumeActivity的操作,
这里我省略了一些ActivityStack文件中的函数的跳转,直接看下面关键的节点函数:

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);

    r.task.stack.setLaunchTime(r);

    if (app != null && app.thread != null) {
        try {
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                    || !"android".equals(r.info.packageName)) {
                // Don't add this if it is a platform component that is marked
                // to run in multiple processes, because this is actually
                // part of the framework so doesn't make sense to track as a
                // separate apk in the process.
                app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                        mService.mProcessStats);
            }
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }

    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

这里的判断if (app != null && app.thread !=
null)中的两个变量在前面已经介绍过,
如果应用程序已经启动,在内部进行跳转的时候,这两个变量都是不为空的,
那么,我们就进入了realStartActivityLocked这个函数,
这个函数则会执行如下代码:

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

这段代码和上面app.thread.schedulePauseActivity非常相似,
这里也是通过Binder机制,又从服务端通知客户端ApplicationThread去执行scheduleLaunchActivity:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    Activity a = performLaunchActivity(r, customIntent);
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }
            }
            r.paused = true;

            mActivities.put(r.token, r);

        } 
    }
}

performLaunchActivity通过ClassLoader类加载机制生成Activity对象,然后通过Instrumentation去执行生命周期的函数,
同时还设置了主题等其他初始化操作。

到这里, 就基本将Activity启动流程走了一遍,
其中重点描述了几次Client与Service交互的操作,对于一些函数内部的实现没有深入分析,仅仅是走了一遍流程,在此做一些记录。

的updateLocale()函数中调用,源码如下:

2. Application初始化

AMS通过Process孵化新的进程,并且进程的入口为ActivityThread:

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {

    ....            

    boolean isActivityProcess = (entryPoint == null);
    if (entryPoint == null) entryPoint = "android.app.ActivityThread";

    //此处的app.processName为"android.app.ActivityThread"
    Process.ProcessStartResult startResult = Process.start(entryPoint,app.processName, uid, uid, gids, debugFlags, mountExternal,app.info.targetSdkVersion,app.info.seinfo, requiredAbi, instructionSet,app.info.dataDir, entryPointArgs);

}

Process类启动新的进程,实际上是使用Zygote
fork一个进程,进程的入口为之前所指定的ActivityThread,fork成功后,会调用ActivityThread的main函数,继续查看ActivityThread的main源码:

public static void main(String[] args) {
        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

main函数中做了三件事,初始化MainLooper,创建了ActivityThread对象,调用attach函数,然后整个线程通过Looper.loop()进入无限循环中。查看thread.attach()函数,往ActivityManagerService传递了一个mAppThread对象。

RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }

mAppThread对象是ApplicationThread类型,定义在ActivityThread中,虽然它叫ApplicationThread,但是它并不是一个Thread,熟悉Binder机制的同学,ApplicationThread实际上是一个Binder的实现,将其传递给AMS,使得ActivityThread可以接受AMS发送的各种消息。

mgr.attachApplication(mAppThread)会调用到AMS中同名的方法中:

@Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }

该方法会进一步调用到attachApplicationLocked()方法,该方法会对Application做一系列校验以及初始化工作,然后调用:

thread.bindApplication

回调到ApplicationThread的bindApplication方法,向VM注册运行进程的相关信息,发送了一条消息。。它竟然没有自己处理接下来的事务,此处可以猜想ApplicationThread只是负责接收AMS发送回来的指令,然后具体的处理交还给自己的消息队列进行处理:

public final void bindApplication() {
    if (!sharable) {
        VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir, appInfo.processName);
    }

    AppBindData data = new AppBindData();
    ...
    sendMessage(H.BIND_APPLICATION, data);
}

此处的sendMessage()内部通过mH变量来实现,mH实际上是一个Handler实例,在ActivityThread对象初始化的时候创建:

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

final H mH = new H();    

class H extends Handler {
    ...
}

继续回到ApplicationThread收到bindApplication调用以后,通过mH发送消息让mH来处理:

/**
* H类
*/
public void handleMessage(Message msg) {
    switch(msg.what) {
        case BIND_APPLICATION:
            AppBindData data = (AppBindData)msg.obj;
            handleBindApplication(data);
        break;
    }
}

handleBindApplication方法内最终会实例化一个Application对象出来,按照这个猜想继续往下看:

private void handleBindApplication(AppBindData data) {
    ...
    //此处的data.info为LoadedApk对象
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    ...
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);

    ...

    mInstrumentation = new Instrumentation();

    ...

    //实例化Application
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);

    ...
    mInstrumentation.callApplicationOnCreate(app);
}

通过调用LoadedApk的makeApplication方法创建Application实例:

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
    Application app = null;
    String appClass = mApplicationInfo.className;        

    try {
        java.lang.ClassLoader cl = getClassLoader();

        //创建ContextImpl实例
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

        //传递appContext给Application对象
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }        

查看Instrumentaion的newApplication方法:

 public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    return newApplication(cl.loadClass(className), context);
 }

 static public Application newApplication(Class<?> clazz, Context context)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    Application app = (Application)clazz.newInstance();
    //调用attach方法,将Context传递给mBase
    app.attach(context);
    return app;
}

至此,ContextWrapper类中的mBase变量在这个地方被赋值,mBase为ContextImpl的实例,所有ContextWrapper中相关被代理的方法都可在ContextImpl中找到对应的实现。


/** * Requests the system to update the system locale. Note that the system looks halted for a while during the Locale migration, so the caller need to take care of it. */  
    public static void updateLocale(Locale locale) {  
        try {  
            IActivityManager am = ActivityManagerNative.getDefault();  
            Configuration config = am.getConfiguration();  

            config.locale = locale;  

            // indicate this isn't some passing default - the user wants this remembered 
            config.userSetLocale = true;  

            am.updateConfiguration(config);  
            // Trigger the dirty bit for the Settings Provider. 
            BackupManager.dataChanged("com.android.providers.settings");  
        } catch (RemoteException e) {  
            // Intentionally left blank 
        }  
    }

3.小结

针对Context的实例化:

  • Context实例化是由Framework层完成,常见的Application,Service等本身并没有实现Context中的abstract方法,所有实现交给ContextImpl去实现。
  • Context的继承结构:
![](http://img.blog.csdn.net/20151022212109519?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
Context结构图
  • Application的实例化步骤:
![](http://p1.bpimg.com/1949/8de34a6fb5a3c523.png)
Application实例化时序图
  • 中途经过多道工序:AMS、Process、ActivityThread、ApplicationThread、H、LoadedApk、Instrumentation的加工。

本文为个人见解,如果错误,欢迎指正。

从注释可以看出, 只要本地local改变就会调用该函数.
查看ActivityManagerNative的getDefault()可以看到,
该函数返回的是远程服务对象ActivityManagerServices.java在本地的一个代理.
最终调用的是ActivityManagerService.java中的updateConfiguration()函数.

public void updateConfiguration(Configuration values) {  
        enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,  
                "updateConfiguration()");  

        synchronized(this) {  
            if (values == null && mWindowManager != null) {  
                // sentinel: fetch the current configuration from the window manager 
                values = mWindowManager.computeNewConfiguration();  
            }  

            if (mWindowManager != null) {  
                mProcessList.applyDisplaySize(mWindowManager);  
            }  

            final long origId = Binder.clearCallingIdentity();  
            if (values != null) {  
                Settings.System.clearConfiguration(values);  
            }  
            updateConfigurationLocked(values, null, false, false);  
            Binder.restoreCallingIdentity(origId);  
        }  
    }

该函数, 首先进行的是权限的校验. 然后调用updateConfigurationLocked()函数.

/** * Do either or both things: (1) change the current configuration, and (2) * make sure the given activity is running with the (now) current * configuration. Returns true if the activity has been left running, or * false if <var>starting</var> is being destroyed to match the new * configuration. * @param persistent TODO */  
    public boolean updateConfigurationLocked(Configuration values,  
            ActivityRecord starting, boolean persistent, boolean initLocale) {  
        int changes = 0;  

        boolean kept = true;  

        if (values != null) {  
            Configuration newConfig = new Configuration(mConfiguration);  
            changes = newConfig.updateFrom(values);  
            if (changes != 0) {  
                if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {  
                    Slog.i(TAG, "Updating configuration to: " + values);  
                }  

                EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);  

                if (values.locale != null && !initLocale) {  
                    saveLocaleLocked(values.locale,   
                                     !values.locale.equals(mConfiguration.locale),  
                                     values.userSetLocale, values.simSetLocale);  
                }  

                mConfigurationSeq++;  
                if (mConfigurationSeq <= 0) {  
                    mConfigurationSeq = 1;  
                }  
                newConfig.seq = mConfigurationSeq;  
                mConfiguration = newConfig;  
                Slog.i(TAG, "Config changed: " + newConfig);  

                final Configuration configCopy = new Configuration(mConfiguration);  

                AttributeCache ac = AttributeCache.instance();  
                if (ac != null) {  
                    ac.updateConfiguration(configCopy);  
                }  

                // Make sure all resources in our process are updated 
                // right now, so that anyone who is going to retrieve 
                // resource values after we return will be sure to get 
                // the new ones. This is especially important during 
                // boot, where the first config change needs to guarantee 
                // all resources have that config before following boot 
                // code is executed. 
                mSystemThread.applyConfigurationToResources(configCopy);  

                if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {  
                    Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);  
                    msg.obj = new Configuration(configCopy);  
                    mHandler.sendMessage(msg);  
                }  

                for (int i=mLruProcesses.size()-1; i>=0; i--) {  
                    ProcessRecord app = mLruProcesses.get(i);  
                    try {  
                        if (app.thread != null) {  
                            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "  
                                    + app.processName + " new config " + mConfiguration);  
                            app.thread.scheduleConfigurationChanged(configCopy);  
                        }  
                    } catch (Exception e) {  
                    }  
                }  
                Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);  
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY  
                        | Intent.FLAG_RECEIVER_REPLACE_PENDING);  
                broadcastIntentLocked(null, null, intent, null, null, 0, null, null,  
                        null, false, false, MY_PID, Process.SYSTEM_UID);  
                if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {  
                    broadcastIntentLocked(null, null,  
                            new Intent(Intent.ACTION_LOCALE_CHANGED),  
                            null, null, 0, null, null,  
                            null, false, false, MY_PID, Process.SYSTEM_UID);  
                }  

            }  
        }  

        if (changes != 0 && starting == null) {  
            // If the configuration changed, and the caller is not already 
            // in the process of starting an activity, then find the top 
            // activity to check if its configuration needs to change. 
            starting = mMainStack.topRunningActivityLocked(null);  
        }  

        if (starting != null) {  
            kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);  
            // And we need to make sure at this point that all other activities 
            // are made visible with the correct configuration. 
            mMainStack.ensureActivitiesVisibleLocked(starting, changes);  
        }  

        if (values != null && mWindowManager != null) {  
            mWindowManager.setNewConfiguration(mConfiguration);  
        }  

        return kept;  
    }

整个语言切换就在这个函数中完成. 咋一看似乎没感觉到该函数做了哪些事情.
我们首先来看注释: Do either or both things: (1) change the current
configuration, and (2)

make sure the given activity is running with the (now) current.
configuration大概意思是: 这个函数做了两件事情. (1).
改变当前的configuration.
意思就是让改变的configuration更新到当前configuration. (2)
确保所有正在运行的activity都能更新改变后的configuration.(这点是关键.) .
我们按照这个思路看看android是如何更新configuration. 查看代码 , 首先看到
这个函数首先判断values是否为空, 这里values肯定不为空的, 然后changes =
newConfig.updateFrom(values); 我们看看updateFrom做了什么操作。

/** 
     * Copy the fields from delta into this Configuration object, keeping 
     * track of which ones have changed.  Any undefined fields in 
     * <var>delta</var> are ignored and not copied in to the current 
     * Configuration. 
     * @return Returns a bit mask of the changed fields, as per 
     * {@link #diff}. 
     */  
    public int updateFrom(Configuration delta) {  
        int changed = 0;  
        ...  
        if (delta.locale != null   && (locale == null || !locale.equals(delta.locale))) {  
            changed |= ActivityInfo.CONFIG_LOCALE;  
            locale = delta.locale != null   ? (Locale) delta.locale.clone() : null;  
            textLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);  
        }  
        if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))  
        {  
            userSetLocale = true;  
            changed |= ActivityInfo.CONFIG_LOCALE;  
        }  
        ...  
        return changed;  
    }

因为语言改变了, 那么 (!locale.equals(delta.locale)) 是true. changed
大于0, 然后return changed.
回到ActivityManagerService.java的updateConfigurationLocked函数,
因为changed不为0 , 所以走if这个流程. 继续看代码。

        for (int i=mLruProcesses.size()-1; i>=0; i--) {  
                    ProcessRecord app = mLruProcesses.get(i);  
                    try {  
                        if (app.thread != null) {  
                            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "  
                                    + app.processName + " new config " + mConfiguration);  
                            app.thread.scheduleConfigurationChanged(configCopy);  
                        }  
                    } catch (Exception e) {  
                    }  
                }

首先看到的是mLurProcesses 是ArrayList类型. LRU : Least Recently
Used保存所有运行过的进程. ProcessRecord进程类,
一个apk文件运行时会对应一个进程. app.thread.
此处的thread代表的是ApplicationThreadNative.java类型.
然后调用其scheduleConfigurationChanged(); 查看该函数。

    public final void scheduleConfigurationChanged(Configuration config)  
            throws RemoteException {  
        Parcel data = Parcel.obtain(); 
        data.writeInterfaceToken(IApplicationThread.descriptor); 
        config.writeToParcel(data, 0); 
        mRemote.transact(SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION, data, null, 
                IBinder.FLAG_ONEWAY);  
        data.recycle(); 
    }

又是通过binder调用, 所以 , binder在android中是一个很重要的概念.
此处远程调用的是ActivityThread.java中的私有内部内ApplicationThread。

    private class ApplicationThread extends ApplicationThreadNative {  
        private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";  
        private static final String ONE_COUNT_COLUMN = "%21s %8d";  
        private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";  
        private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";  
        private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";  

        ...  
        public void scheduleConfigurationChanged(Configuration config) {  
            updatePendingConfiguration(config);  
            queueOrSendMessage(H.CONFIGURATION_CHANGED, config);  
        }  
        ...  
}

而ApplicationThread中的handler的CONFIGURATION_CHANGED是调用handleConfigurationChanged()。

    final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {  

       ArrayList<ComponentCallbacks2> callbacks = null;  

    ...         ...  
       applyConfigurationToResourcesLocked(config, compat);  

       ...  

       callbacks = collectComponentCallbacksLocked(false, config);  
       ...  

       if (callbacks != null) {  
           final int N = callbacks.size();  
           for (int i=0; i<N; i++) {  
               performConfigurationChanged(callbacks.get(i), config);  
           }  
       }

这个函数首先是调用applyConfigurationToResourcesLocked().
看函数名大概可以猜想到:
将configuration应用到resources.这里configuration改变的是local 本地语言.
那而resources资源包含语言包吗?

    final boolean applyConfigurationToResourcesLocked(Configuration config,  
            CompatibilityInfo compat) {  

        int changes = mResConfiguration.updateFrom(config);  
        DisplayMetrics dm = getDisplayMetricsLocked(null, true);  

        if (compat != null && (mResCompatibilityInfo == null ||  
                !mResCompatibilityInfo.equals(compat))) {  
            mResCompatibilityInfo = compat;  
            changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT  
                    | ActivityInfo.CONFIG_SCREEN_SIZE  
                    | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;  
        }  

        ...  

        Resources.updateSystemConfiguration(config, dm, compat);  

        ...  

        Iterator<WeakReference<Resources>> it =  
            mActiveResources.values().iterator();  
        while (it.hasNext()) {  
            WeakReference<Resources> v = it.next();  
            Resources r = v.get();  
            if (r != null) {  
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "  
                        + r + " config to: " + config);  
                r.updateConfiguration(config, dm, compat);  
                //Slog.i(TAG, "Updated app resources " + v.getKey()  
                //        + " " + r + ": " + r.getConfiguration());  
            } else {  
                //Slog.i(TAG, "Removing old resources " + v.getKey());  
                it.remove();  
            }  
        }  

        return changes != 0;  
    }

Resources.updateSystemConfiguration()清除一部分系统资源,
并且将config更新到Resources, 而Resources包含了一个AssetManager对象,
该对象的核心实现是在AssetManager.cpp中完成的.
然后循环清空mActivityResources资源.
再回到handleConfigurationChanged()函数,
执行完updateSystemConfiguration后, 会循环该进程的所有activity:

if (callbacks != null) {   
final int N = callbacks.size();
        for (int i=0; i<N; i++) {
            performConfigurationChanged(callbacks.get(i), config);
        }
    }

再来看performConfigurationChanged的实现:

private final void performConfigurationChanged(  
            ComponentCallbacks2 cb, Configuration config) {  
        // Only for Activity objects, check that they actually call up to their 
        // superclass implementation. ComponentCallbacks2 is an interface, so 
        // we check the runtime type and act accordingly. 
        Activity activity = (cb instanceof Activity) ? (Activity) cb : null;  
        if (activity != null) {  
            activity.mCalled = false;  
        }  

        boolean shouldChangeConfig = false;  
        if ((activity == null) || (activity.mCurrentConfig == null)) {  
            shouldChangeConfig = true;  
        } else {  

            // If the new config is the same as the config this Activity 
            // is already running with then don't bother calling 
            // onConfigurationChanged 
            int diff = activity.mCurrentConfig.diff(config);  
            if (diff != 0) {  
                // If this activity doesn't handle any of the config changes 
                // then don't bother calling onConfigurationChanged as we're 
                // going to destroy it. 
                if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {  
                    shouldChangeConfig = true;  
                }  
            }  
        }  

        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Config callback " + cb  
                + ": shouldChangeConfig=" + shouldChangeConfig);  
        if (shouldChangeConfig) {  
            cb.onConfigurationChanged(config);  

            if (activity != null) {  
                if (!activity.mCalled) {  
                    throw new SuperNotCalledException(  
                            "Activity " + activity.getLocalClassName() +  
                        " did not call through to super.onConfigurationChanged()");  
                }  
                activity.mConfigChangeFlags = 0;  
                activity.mCurrentConfig = new Configuration(config);  
            }  
        }  
    }

该函数判断configuration是否改变, 如果改变那么shouldChangeConfig为true.
然后调用activity的onConfigurationChange(config);

/** 
    * Called by the system when the device configuration changes while your 
    * activity is running.  Note that this will <em>only</em> be called if 
    * you have selected configurations you would like to handle with the 
    * {@link android.R.attr#configChanges} attribute in your manifest. If 
    * any configuration change occurs that is not selected to be reported 
    * by that attribute, then instead of reporting it the system will stop 
    * and restart the activity (to have it launched with the new 
    * configuration). 
    *  
    * <p>At the time that this function has been called, your Resources 
    * object will have been updated to return resource values matching the 
    * new configuration. 
    *  
    * @param newConfig The new device configuration. 
    */  
   public void onConfigurationChanged(Configuration newConfig) {  
       mCalled = true;  

       mFragments.dispatchConfigurationChanged(newConfig);  

       if (mWindow != null) {  
           // Pass the configuration changed event to the window  
           mWindow.onConfigurationChanged(newConfig);  
       }  

       if (mActionBar != null) {  
           // Do this last; the action bar will need to access  
           // view changes from above.  
           mActionBar.onConfigurationChanged(newConfig);  
       }  
   }

查看注释, 大概意思是: 如果你的activity运行 ,
设备信息有改变(即configuration改变)时由系统调用.
如果你在manifest.xml中配置了configChnages属性则表示有你自己来处理configuration
change. 否则就重启当前这个activity. 而重启之前, 旧的resources已经被清空,
那么就会装载新的资源, 整个过程就完成了语言切换后 ,
能够让所有app使用新的语言。

上面这些就是对Android
系统里面的语言切换进行了源码分析,就先分析到这里;有些东西我也不是很看懂,能力有限~

发表评论

电子邮件地址不会被公开。 必填项已用*标注