Android应用程序窗口设计框架介绍

转载:https://blog.csdn.net/yangwen123/article/details/35987609

在Android系统中,一个Activity对应一个应用程序窗口,任何一个Activity的启动都是由AMS服务和应用程序进程相互配合来完成的。AMS服务统一调度系统中所有进程的Activity启动,而每个Activity的启动过程则由其所属进程来完成。AMS服务通过realStartActivityLocked函数来通知应用程序进程启动某个Activity:

frameworks\base\services\java\com\android\server\am\ ActivityStack.java


 
 
  1. final boolean realStartActivityLocked(ActivityRecord r,
  2. ProcessRecord app, boolean andResume, boolean checkConfig)
  3. throws RemoteException {
  4. ...
  5. //系统参数发送变化,通知Activity
  6. if (checkConfig) {
  7. ①Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(mService.mConfiguration,
  8. r.mayFreezeScreenLocked(app) ? r.appToken : null);
  9. mService.updateConfigurationLocked(config, r, false, false);
  10. }
  11. //将进程描述符设置到启动的Activity描述符中
  12. r.app = app;
  13. app.waitingToKill = null;
  14. //将启动的Activity添加到进程启动的Activity列表中
  15. int idx = app.activities.indexOf(r);
  16. if (idx < 0) {
  17. app.activities.add(r);
  18. }
  19. mService.updateLruProcessLocked(app, true, true);
  20. try {
  21. ...
  22. //通知应用程序进程加载Activity
  23. ②app.thread.scheduleLaunchActivity( new Intent(r.intent), r.appToken,
  24. System.identityHashCode(r), r.info,
  25. new Configuration(mService.mConfiguration),
  26. r.compat, r.icicle, results, newIntents, !andResume,
  27. mService.isNextTransitionForward(), profileFile, profileFd,
  28. profileAutoStop);
  29. ...
  30. } catch (RemoteException e) {
  31. ...
  32. }
  33. if (mMainStack) {
  34. mService.startSetupActivityLocked();
  35. }
  36. return true;
  37. }

AMS通过realStartActivityLocked函数来调度应用程序进程启动一个Activity,参数r为即将启动的Activity在AMS服务中的描述符,参数app为Activity运行所在的应用程序进程在AMS服务中的描述符。函数通过IApplicationThread代理对象ApplicationThreadProxy通知应用程序进程启动r对应的Activity,应用程序进程完成Activity的加载等准备工作后,AMS最后启动该Activity。启动Activity的创建等工作是在应用程序进程中完成的,AMS是通过IApplicationThread接口和应用程序进程通信的。r.appToken 在AMS服务端的类型为Token,是IApplicationToken的Binder本地对象。

frameworks\base\core\java\android\app\ ActivityThread.java


 
 
  1. public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
  2. ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
  3. Bundle state, List<ResultInfo> pendingResults,
  4. List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
  5. String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
  6. //将AMS服务传过来的参数封装为ActivityClientRecord对象
  7. ActivityClientRecord r = new ActivityClientRecord();
  8. r.token = token;
  9. r.ident = ident;
  10. r.intent = intent;
  11. r.activityInfo = info;
  12. r.compatInfo = compatInfo;
  13. r.state = state;
  14. r.pendingResults = pendingResults;
  15. r.pendingIntents = pendingNewIntents;
  16. r.startsNotResumed = notResumed;
  17. r.isForward = isForward;
  18. r.profileFile = profileName;
  19. r.profileFd = profileFd;
  20. r.autoStopProfiler = autoStopProfiler;
  21. updatePendingConfiguration(curConfig);
  22. //使用异步消息方式实现Activity的启动
  23. queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
  24. }

参数token从AMS服务端经过Binder传输到应用程序进程后,变为IApplicationToken的Binder代理对象,类型为IApplicationToken.Proxy,这是因为AMS和应用程序运行在不同的进程中。

通过queueOrSendMessage函数将Binder跨进程调用转换为应用程序进程中的异步消息处理

frameworks\base\core\java\android\app\ ActivityThread.java


 
 
  1. private class H extends Handler {
  2. public void handleMessage(Message msg) {
  3. switch (msg.what) {
  4. case LAUNCH_ACTIVITY: {
  5. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
  6. ActivityClientRecord r = (ActivityClientRecord)msg.obj;
  7. r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
  8. handleLaunchActivity(r, null);
  9. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
  10. } break;
  11. }
  12. }
  13. }

LAUNCH_ACTIVITY消息在应用程序主线程消息循环中得到处理,应用程序通过handleLaunchActivity函数来启动Activity。到此AMS服务就完成了Activity的调度任务,将Activity的启动过程完全交给了应用程序进程来完成。

frameworks\base\core\java\android\app\ ActivityThread.java


 
 
  1. private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  2. //主线程空闲时会定时执行垃圾回收,主线程当前要完成启动Activity的任务,因此这里先暂停GC
  3. unscheduleGcIdler();
  4. if (r.profileFd != null) {
  5. mProfiler.setProfiler(r.profileFile, r.profileFd);
  6. mProfiler.startProfiling();
  7. mProfiler.autoStopProfiler = r.autoStopProfiler;
  8. }
  9. // Make sure we are running with the most recent config.
  10. ①handleConfigurationChanged( null, null);
  11. //创建Activity
  12. ②Activity a = performLaunchActivity(r, customIntent);
  13. if (a != null) {
  14. r.createdConfig = new Configuration(mConfiguration);
  15. Bundle oldState = r.state;
  16. //启动Activity
  17. ③handleResumeActivity(r.token, false, r.isForward);
  18. ...
  19. } else{
  20. ...
  21. }
  22. }

performLaunchActivity

应用程序进程通过performLaunchActivity函数将即将要启动的Activity加载到当前进程空间来,同时为启动Activity做准备。

frameworks\base\core\java\android\app\ ActivityThread.java


 
 
  1. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  2. ActivityInfo aInfo = r.activityInfo;
  3. if (r.packageInfo == null) {
  4. //通过Activity所在的应用程序信息及该Activity对应的CompatibilityInfo信息从PMS服务中查询当前Activity的包信息
  5. r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);
  6. }
  7. //获取当前Activity的组件信息
  8. ComponentName component = r.intent.getComponent();
  9. if (component == null) {
  10. component = r.intent.resolveActivity(mInitialApplication.getPackageManager());
  11. r.intent.setComponent(component);
  12. }
  13. if (r.activityInfo.targetActivity != null) {
  14. //packageName为启动Activity的包名,targetActivity为Activity的类名
  15. component = new ComponentName(r.activityInfo.packageName,
  16. r.activityInfo.targetActivity);
  17. }
  18. //通过类反射方式加载即将启动的Activity
  19. Activity activity = null;
  20. try {
  21. java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
  22. ①activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
  23. StrictMode.incrementExpectedActivityCount(activity.getClass());
  24. r.intent.setExtrasClassLoader(cl);
  25. if (r.state != null) {
  26. r.state.setClassLoader(cl);
  27. }
  28. } catch (Exception e) {
  29. ...
  30. }
  31. try {
  32. //通过单例模式为应用程序进程创建Application对象
  33. ②Application app = r.packageInfo.makeApplication( false, mInstrumentation);
  34. if (activity != null) {
  35. //为当前Activity创建上下文对象ContextImpl
  36. ContextImpl appContext = new ContextImpl();
  37. //上下文初始化
  38. ③appContext.init(r.packageInfo, r.token, this);
  39. appContext.setOuterContext(activity);
  40. CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
  41. ...
  42. Configuration config = new Configuration(mCompatConfiguration);
  43. //将当前启动的Activity和上下文ContextImpl、Application绑定
  44. ④activity.attach(appContext, this, getInstrumentation(), r.token,
  45. r.ident, app, r.intent, r.activityInfo, title, r.parent,
  46. r.embeddedID, r.lastNonConfigurationInstances, config);
  47. ...
  48. //调用Activity的OnCreate函数
  49. ⑤mInstrumentation.callActivityOnCreate(activity, r.state);
  50. ...
  51. //将Activity保存到ActivityClientRecord中,ActivityClientRecord为Activity在应用程序进程中的描述符
  52. r.activity = activity;
  53. ...
  54. }
  55. r.paused = true;
  56. //ActivityThread的成员变量mActivities保存了当前应用程序进程中的所有Activity的描述符
  57. mActivities.put(r.token, r);
  58. } catch (SuperNotCalledException e) {
  59. ...
  60. }
  61. return activity;
  62. }

在该函数中,首先通过PMS服务查找到即将启动的Activity的包名信息,然后通过类反射方式创建一个该Activity实例,同时为应用程序启动的每一个Activity创建一个LoadedApk实例对象,应用程序进程中创建的所有LoadedApk对象保存在ActivityThread的成员变量mPackages中。接着通过LoadedApk对象的makeApplication函数,使用单例模式创建Application对象,因此在android应用程序进程中有且只有一个Application实例。然后为当前启动的Activity创建一个ContextImpl上下文对象,并初始化该上下文,到此我们可以知道,启动一个Activity需要以下对象:

1)      XXActivity对象,需要启动的Activity;

2)      LoadedApk对象,每个启动的Activity都拥有属于自身的LoadedApk对象;

3)      ContextImpl对象,每个启动的Activity都拥有属于自身的ContextImpl对象;

4)      Application对象,应用程序进程中有且只有一个实例,和Activity是一对多的关系;

加载Activity类


 
 
  1. public Activity newActivity(ClassLoader cl, String className,
  2. Intent intent)
  3. throws InstantiationException, IllegalAccessException,
  4. ClassNotFoundException {
  5. return (Activity)cl.loadClass(className).newInstance();
  6. }

这里通过类反射的方式来加载要启动的Activity实例对象。

LoadedApk构造过程

首先介绍一下LoadedApk对象的构造过程:

frameworks\base\core\java\android\app\ ActivityThread.java


 
 
  1. public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
  2. int flags) {
  3. synchronized (mPackages) {
  4. //通过Activity的包名从对应的成员变量中查找LoadedApk对象
  5. WeakReference<LoadedApk> ref;
  6. if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
  7. ref = mPackages.get(packageName);
  8. } else {
  9. ref = mResourcePackages.get(packageName);
  10. }
  11. LoadedApk packageInfo = ref != null ? ref.get() : null;
  12. if (packageInfo != null && (packageInfo.mResources == null
  13. || packageInfo.mResources.getAssets().isUpToDate())) {
  14. ...
  15. return packageInfo;
  16. }
  17. }
  18. //如果没有,则为当前Activity创建对应的LoadedApk对象
  19. ApplicationInfo ai = null;
  20. try {
  21. //通过包名在PMS服务中查找应用程序信息
  22. ai = getPackageManager().getApplicationInfo(packageName,
  23. PackageManager.GET_SHARED_LIBRARY_FILES, UserId.myUserId());
  24. } catch (RemoteException e) {
  25. // Ignore
  26. }
  27. //使用另一个重载函数创建LoadedApk对象
  28. if (ai != null) {
  29. return getPackageInfo(ai, compatInfo, flags);
  30. }
  31. return null;
  32. }


 


 
 
  1. public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
  2. int flags) {
  3. boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
  4. boolean securityViolation = includeCode && ai.uid != 0
  5. && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
  6. ? !UserId.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
  7. : true);
  8. if ((flags&(Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY))
  9. == Context.CONTEXT_INCLUDE_CODE) {
  10. ...
  11. }
  12. return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode);
  13. }


 


 
 
  1. private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
  2. ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
  3. //再次从对应的成员变量中查找LoadedApk实例
  4. synchronized (mPackages) {
  5. WeakReference<LoadedApk> ref;
  6. if (includeCode) {
  7. ref = mPackages.get(aInfo.packageName);
  8. } else {
  9. ref = mResourcePackages.get(aInfo.packageName);
  10. }
  11. LoadedApk packageInfo = ref != null ? ref.get() : null;
  12. if (packageInfo == null || (packageInfo.mResources != null
  13. && !packageInfo.mResources.getAssets().isUpToDate())) {
  14. ...
  15. //构造一个LoadedApk对象
  16. packageInfo = new LoadedApk( this, aInfo, compatInfo, this, baseLoader,
  17. securityViolation, includeCode &&
  18. (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
  19. //保存LoadedApk实例到ActivityThread的相应成员变量中
  20. if (includeCode) {
  21. mPackages.put(aInfo.packageName,
  22. new WeakReference<LoadedApk>(packageInfo));
  23. } else {
  24. mResourcePackages.put(aInfo.packageName,
  25. new WeakReference<LoadedApk>(packageInfo));
  26. }
  27. }
  28. return packageInfo;
  29. }
  30. }

 

frameworks\base\core\java\android\app\LoadedApk.java


 
 
  1. public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
  2. CompatibilityInfo compatInfo,
  3. ActivityThread mainThread, ClassLoader baseLoader,
  4. boolean securityViolation, boolean includeCode) {
  5. mActivityThread = activityThread;
  6. mApplicationInfo = aInfo;
  7. mPackageName = aInfo.packageName;
  8. mAppDir = aInfo.sourceDir;
  9. final int myUid = Process.myUid();
  10. mResDir = aInfo.uid == myUid ? aInfo.sourceDir
  11. : aInfo.publicSourceDir;
  12. if (!UserId.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
  13. aInfo.dataDir = PackageManager.getDataDirForUser(UserId.getUserId(myUid),
  14. mPackageName);
  15. }
  16. mSharedLibraries = aInfo.sharedLibraryFiles;
  17. mDataDir = aInfo.dataDir;
  18. mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
  19. mLibDir = aInfo.nativeLibraryDir;
  20. mBaseClassLoader = baseLoader;
  21. mSecurityViolation = securityViolation;
  22. mIncludeCode = includeCode;
  23. mCompatibilityInfo.set(compatInfo);
  24. if (mAppDir == null) {
  25. //为应用程序进程创建一个ContextImpl上下文
  26. if (ActivityThread.mSystemContext == null) {
  27. ActivityThread.mSystemContext =
  28. ContextImpl.createSystemContext(mainThread);
  29. ActivityThread.mSystemContext.getResources().updateConfiguration(
  30. mainThread.getConfiguration(),
  31. mainThread.getDisplayMetricsLocked(compatInfo, false),
  32. compatInfo);
  33. }
  34. mClassLoader = ActivityThread.mSystemContext.getClassLoader();
  35. mResources = ActivityThread.mSystemContext.getResources();
  36. }
  37. }

从以上LoadedApk的构造函数可以看出,LoadedApk类记录了Activity运行所在的ActivityThread、Activity所在的应用程序信息、Activity的包名、Activity的资源路径、Activity的库路径、Activity的数据存储路径、类加载器和应用程序所使用的资源等信息。

Application构造过程

当Activity为应用程序进程启动的第一个Activity,因此需要构造一个Application对象

frameworks\base\core\java\android\app\LoadedApk.java


 
 
  1. public Application makeApplication(boolean forceDefaultAppClass,
  2. Instrumentation instrumentation) {
  3. //在应用程序进程空间以单例模式创建Application对象
  4. if (mApplication != null) {
  5. return mApplication;
  6. }
  7. Application app = null;
  8. //得到应用程序的Application类名
  9. String appClass = mApplicationInfo.className;
  10. //如果应用程序没用重写Application,则使用Android默认的Application类
  11. if (forceDefaultAppClass || (appClass == null)) {
  12. appClass = "android.app.Application";
  13. }
  14. try {
  15. java.lang.ClassLoader cl = getClassLoader();
  16. //为Application实例创建一个上下文对象ContextImpl
  17. ①ContextImpl appContext = new ContextImpl();
  18. //初始化上下文
  19. ②appContext.init( this, null, mActivityThread);
  20. //创建Application实例对象
  21. ③app = mActivityThread.mInstrumentation.newApplication(
  22. cl, appClass, appContext);
  23. appContext.setOuterContext(app);
  24. } catch (Exception e) {
  25. ...
  26. }
  27. mActivityThread.mAllApplications.add(app);
  28. mApplication = app;
  29. if (instrumentation != null) {
  30. try {
  31. //调用Application的OnCreate函数
  32. ④instrumentation.callApplicationOnCreate(app);
  33. } catch (Exception e) {
  34. ...
  35. }
  36. }
  37. return app;
  38. }

在应用程序开发过程中,当我们重写了Application类后,应用程序加载运行的是我们定义的Application类,否则就加载运行默认的Application类。从Application对象的构造过程就可以解释为什么应用程序启动后首先执行的是Application的OnCreate函数。在实例化Application对象时,同样创建并初始化了一个ContextImpl上下文对象。

ContextImpl构造过程

前面我们介绍了,每一个Activity拥有一个上下文对象ContextImpl,每一个Application对象也拥有一个ContextImpl上下文对象,那么ContextImpl对象又是如何构造的呢?

frameworks\base\core\java\android\app\ ContextImpl.java


 
 
  1. ContextImpl() {
  2. mOuterContext = this;
  3. }

ContextImpl的构造过程什么也没干,通过调用ContextImpl的init函数进行初始化


 
 
  1. final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread) {
  2. init(packageInfo, activityToken, mainThread, null, null);
  3. }

 


 
 
  1. final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread,
  2. Resources container, String basePackageName) {
  3. mPackageInfo = packageInfo;
  4. mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
  5. mResources = mPackageInfo.getResources(mainThread);
  6. if (mResources != null && container != null
  7. && container.getCompatibilityInfo().applicationScale !=
  8. mResources.getCompatibilityInfo().applicationScale) {
  9. mResources = mainThread.getTopLevelResources(
  10. mPackageInfo.getResDir(), container.getCompatibilityInfo());
  11. }
  12. mMainThread = mainThread;
  13. mContentResolver = new ApplicationContentResolver( this, mainThread);
  14. setActivityToken(activityToken);
  15. }

从ContextImpl的初始化函数中可以知道,ContextImpl记录了应用程序的包名信息、应用程序的资源信息、应用程序的主线程、ContentResolver及Activity对应的IApplicationToken.Proxy,当然对应Application对象所拥有的ContextImpl上下文就没有对应的Token了。通过前面的分析我们可以知道各个对象之间的关系:


对象Attach过程

Activity所需要的对象都创建好了,就需要将Activity和Application对象、ContextImpl对象绑定在一起。

frameworks\base\core\java\android\app\ Activity.java


 
 
  1. final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
  2. Application application, Intent intent, ActivityInfo info, CharSequence title,
  3. Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances,
  4. Configuration config) {
  5. attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id,
  6. lastNonConfigurationInstances, config);
  7. }

context:Activity的上下文对象,就是前面创建的ContextImpl对象;

aThread:Activity运行所在的主线程描述符ActivityThread;

instr:用于监控Activity运行状态的Instrumentation对象;

token:用于和AMS服务通信的IApplicationToken.Proxy代理对象;

application:Activity运行所在进程的Application对象;

parent:启动当前Activity的Activity;


 
 
  1. final void attach(Context context, ActivityThread aThread,
  2. Instrumentation instr, IBinder token, int ident,
  3. Application application, Intent intent, ActivityInfo info,
  4. CharSequence title, Activity parent, String id,
  5. NonConfigurationInstances lastNonConfigurationInstances,
  6. Configuration config) {
  7. //将上下文对象ContextImpl保存到Activity的成员变量中
  8. attachBaseContext(context);
  9. //每个Activity都拥有一个FragmentManager,这里就是将当前Activity设置到FragmentManager中管理
  10. mFragments.attachActivity( this);
  11. //创建窗口对象
  12. ①mWindow = PolicyManager.makeNewWindow( this);
  13. mWindow.setCallback( this);
  14. mWindow.getLayoutInflater().setPrivateFactory( this);
  15. if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
  16. mWindow.setSoftInputMode(info.softInputMode);
  17. }
  18. if (info.uiOptions != 0) {
  19. mWindow.setUiOptions(info.uiOptions);
  20. }
  21. //记录应用程序的UI线程
  22. mUiThread = Thread.currentThread();
  23. //记录应用程序的ActivityThread对象
  24. mMainThread = aThread;
  25. mInstrumentation = instr;
  26. mToken = token;
  27. mIdent = ident;
  28. mApplication = application;
  29. mIntent = intent;
  30. mComponent = intent.getComponent();
  31. mActivityInfo = info;
  32. mTitle = title;
  33. mParent = parent;
  34. mEmbeddedID = id;
  35. mLastNonConfigurationInstances = lastNonConfigurationInstances;
  36. //为Activity所在的窗口创建窗口管理器
  37. ②mWindow.setWindowManager( null, mToken, mComponent.flattenToString(),
  38. (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
  39. if (mParent != null) {
  40. mWindow.setContainer(mParent.getWindow());
  41. }
  42. mWindowManager = mWindow.getWindowManager();
  43. mCurrentConfig = config;
  44. }

在该attach函数中主要做了以下几件事:

1)        将Activity设置到FragmentManager中;

2)        根据参数初始化Activity的成员变量;

3)        为Activity创建窗口Window对象;

4)        为Window创建窗口管理器;

到此为止应用程序进程为启动的Activity对象创建了以下不同的实例对象,它们之间的关系如下:

应用程序窗口创建过程

frameworks\base\core\java\com\android\internal\policy\ PolicyManager.java


 
 
  1. public static Window makeNewWindow(Context context) {
  2. return sPolicy.makeNewWindow(context);
  3. }

通过Policy类的makeNewWindow函数来创建一个应用程序窗口


 
 
  1. private static final String POLICY_IMPL_CLASS_NAME =
  2. "com.android.internal.policy.impl.Policy";
  3. private static final IPolicy sPolicy;
  4. static {
  5. try {
  6. Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
  7. sPolicy = (IPolicy)policyClass.newInstance();
  8. } catch (ClassNotFoundException ex) {
  9. ...
  10. }
  11. }

frameworks\base\policy\src\com\android\internal\policy\impl\ Policy.java


 
 
  1. public Window makeNewWindow(Context context) {
  2. return new PhoneWindow(context);
  3. }

应用程序窗口的创建过程其实就是构造一个PhoneWindow对象。PhoneWindow类是通过静态方式加载到应用程序进程空间的。


 
 
  1. private static final String[] preload_classes = {
  2. "com.android.internal.policy.impl.PhoneLayoutInflater",
  3. "com.android.internal.policy.impl.PhoneWindow",
  4. "com.android.internal.policy.impl.PhoneWindow$1",
  5. "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback",
  6. "com.android.internal.policy.impl.PhoneWindow$DecorView",
  7. "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
  8. "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
  9. };

 
 
  1. static {
  2. for (String s : preload_classes) {
  3. try {
  4. Class.forName(s);
  5. } catch (ClassNotFoundException ex) {
  6. Log.e(TAG, "Could not preload class for phone policy: " + s);
  7. }
  8. }
  9. }

PhoneWindow的构造过程


 
 
  1. public PhoneWindow(Context context) {
  2. super(context);
  3. mAlternativePanelStyle=getContext().getResources().getBoolean(com.android.internal.R.bool.config_alternativePanelStyle);
  4. mLayoutInflater = LayoutInflater.from(context);
  5. }

构造过程比较简单,只是得到布局加载服务对象。

窗口管理器创建过程

通过前面的分析我们可以知道,在Activity启动过程中,会为Activity创建一个窗口对象PhoneWindow,应用程序有了窗口那就需要有一个窗口管理器来管理这些窗口,因此在Activity启动过程中还会创建一个WindowManager对象。

frameworks\base\core\java\android\view\ Window.java


 
 
  1. public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
  2. boolean hardwareAccelerated) {
  3. mAppToken = appToken; // IApplicationToken.Proxy代理对象
  4. mAppName = appName;
  5. //得到WindowManagerImpl实例,
  6. if (wm == null) {
  7. wm = WindowManagerImpl.getDefault();
  8. }
  9. //为每个启动的Activity创建一个轻量级的窗口管理器LocalWindowManager
  10. mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
  11. }

WindowManagerImpl为重量级的窗口管理器,应用程序进程中有且只有一个WindowManagerImpl实例,它管理了应用程序进程中创建的所有PhoneWindow窗口。Activity并没有直接引用WindowManagerImpl实例,Android系统为每一个启动的Activity创建了一个轻量级的窗口管理器LocalWindowManager,每个Activity通过LocalWindowManager来访问WindowManagerImpl,它们三者之间的关系如下图所示:

WindowManagerImpl以单例模式创建,应用程序进程中有且只有一个WindowManagerImpl实例

frameworks\base\core\java\android\view\ WindowManagerImpl.java


 
 
  1. private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
  2. public static WindowManagerImpl getDefault() {
  3. return sWindowManager;
  4. }

应用程序进程会为每一个Activity创建一个LocalWindowManager实例对象

frameworks\base\core\java\android\view\ Window.java


 
 
  1. LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
  2. super(wm, getCompatInfo(mContext));
  3. mHardwareAccelerated = hardwareAccelerated ||
  4. SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
  5. }

frameworks\base\core\java\android\view\ WindowManagerImpl.java     


 
 
  1. CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
  2. mWindowManager = wm instanceof CompatModeWrapper
  3. ? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
  4. if (ci == null) {
  5. mDefaultDisplay = mWindowManager.getDefaultDisplay();
  6. } else {
  7. mDefaultDisplay = Display.createCompatibleDisplay(
  8. mWindowManager.getDefaultDisplay().getDisplayId(), ci);
  9. }
  10. mCompatibilityInfo = ci;
  11. }


 
 
  1. public Display getDefaultDisplay() {
  2. return new Display(Display.DEFAULT_DISPLAY, null);
  3. }

frameworks\base\core\java\android\view\Display.java


 
 
  1. Display( int display, CompatibilityInfoHolder compatInfo) {
  2. synchronized (sStaticInit) {
  3. if (!sInitialized) {
  4. nativeClassInit();
  5. sInitialized = true;
  6. }
  7. }
  8. mCompatibilityInfo = compatInfo != null ? compatInfo : new CompatibilityInfoHolder();
  9. mDisplay = display;
  10. init(display);
  11. }

构造Display对象时需要初始化该对象。

frameworks\base\core\jni\android_view_Display.cpp


 
 
  1. static void android_view_Display_init(
  2. JNIEnv* env, jobject clazz, jint dpy)
  3. {
  4. DisplayInfo info;
  5. if (headless) {
  6. // initialize dummy display with reasonable values
  7. info.pixelFormatInfo.format = 1; // RGB_8888
  8. info.fps = 60;
  9. info.density = 160;
  10. info.xdpi = 160;
  11. info.ydpi = 160;
  12. } else {
  13. status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
  14. if (err < 0) {
  15. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  16. return;
  17. }
  18. }
  19. env->SetIntField(clazz, offsets.pixelFormat,info.pixelFormatInfo.format);
  20. env->SetFloatField(clazz, offsets.fps, info.fps);
  21. env->SetFloatField(clazz, offsets.density, info.density);
  22. env->SetFloatField(clazz, offsets.xdpi, info.xdpi);
  23. env->SetFloatField(clazz, offsets.ydpi, info.ydpi);
  24. }

Display的初始化过程很简单,就是通过SurfaceComposerClient请求SurfaceFlinger得到显示屏的基本信息。

frameworks\native\libs\gui\ SurfaceComposerClient.cpp


 
 
  1. status_t SurfaceComposerClient::getDisplayInfo(
  2. DisplayID dpy, DisplayInfo* info)
  3. {
  4. if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
  5. return BAD_VALUE;
  6. volatile surface_flinger_cblk_t const * cblk = get_cblk();
  7. volatile display_cblk_t const * dcblk = cblk->displays + dpy;
  8. info->w = dcblk->w;
  9. info->h = dcblk->h;
  10. info->orientation = dcblk->orientation;
  11. info->xdpi = dcblk->xdpi;
  12. info->ydpi = dcblk->ydpi;
  13. info->fps = dcblk->fps;
  14. info->density = dcblk->density;
  15. return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
  16. }

我们知道在SurfaceFlinger启动过程中,创建了一块匿名共享内存来保存显示屏的基本信息,这里就是通过访问这块匿名共享内存来读取显示屏信息。到此一个Activity所需要的窗口对象就创建完成了,在应用程序窗口的创建过程中一共创建了以下几个对象:


Activity视图对象的创建过程

在Activity的attach函数中完成应用程序窗口的创建后,通过Instrumentation回调Activity的OnCreate函数来为当前Activity加载布局文件,进一步创建视图对象。

frameworks\base\core\java\android\app\Instrumentation.java


 
 
  1. public void callActivityOnCreate(Activity activity, Bundle icicle) {
  2. ...
  3. activity.performCreate(icicle);
  4. ...
  5. }

frameworks\base\core\java\android\app\Activity.java


 
 
  1. final void performCreate(Bundle icicle) {
  2. onCreate(icicle);
  3. mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
  4. com.android.internal.R.styleable.Window_windowNoDisplay, false);
  5. mFragments.dispatchActivityCreated();
  6. }

我们知道在应用程序开发中,需要重写Activity的OnCreate函数:

Packages\apps\xxx\src\com\xxx\ xxxActivity.java


 
 
  1. public void onCreate(Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. setContentView(R.layout.main_activity);
  4. ...
  5. }

在OnCreate函数中通过setContentView来设置Activity的布局文件,就是生成该Activity的所有视图对象。

frameworks\base\core\java\android\app\Activity.java


 
 
  1. public void setContentView(View view, ViewGroup.LayoutParams params) {
  2. getWindow().setContentView(view, params);
  3. //初始化动作条
  4. initActionBar();
  5. }

getWindow()函数得到前面创建的窗口对象PhoneWindow,通过PhoneWindow来设置Activity的视图。

frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java


 
 
  1. public void setContentView(int layoutResID) {
  2. //如果窗口顶级视图对象为空,则创建窗口视图对象
  3. if (mContentParent == null) {
  4. installDecor();
  5. } else { //否则只是移除该视图对象中的其他视图
  6. mContentParent.removeAllViews();
  7. }
  8. //加载布局文件,并将布局文件中的所有视图对象添加到mContentParent容器中
  9. mLayoutInflater.inflate(layoutResID, mContentParent);
  10. final Callback cb = getCallback();
  11. if (cb != null && !isDestroyed()) {
  12. cb.onContentChanged();
  13. }
  14. }

PhoneWindow的成员变量mContentParent的类型为ViewGroup,是窗口内容存放的地方

frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java


 
 
  1. private void installDecor() {
  2. if (mDecor == null) {
  3. ①mDecor = generateDecor();
  4. mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
  5. mDecor.setIsRootNamespace( true);
  6. if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
  7. mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
  8. }
  9. }
  10. if (mContentParent == null) {
  11. ②mContentParent = generateLayout(mDecor);
  12. mDecor.makeOptionalFitsSystemWindows();
  13. //应用程序窗口标题栏
  14. mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
  15. if (mTitleView != null) {
  16. ...
  17. } else {
  18. //应用程序窗口动作条
  19. mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
  20. if (mActionBar != null) {
  21. ...
  22. }
  23. }
  24. }
  25. }

通过函数generateDecor()来创建一个DecorView对象


 
 
  1. protected DecorView generateDecor() {
  2. return new DecorView(getContext(), - 1);
  3. }

接着通过generateLayout(mDecor)来创建视图对象容器mContentParent


 
 
  1. protected ViewGroup generateLayout(DecorView decor) {
  2. //通过读取属性配置文件设置窗口风格
  3. if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) {
  4. requestFeature(FEATURE_ACTION_BAR_OVERLAY);
  5. }
  6. ...
  7. //通过读取属性配置文件设置窗口标志
  8. if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
  9. setFlags(FLAG_FULLSCREEN,FLAG_FULLSCREEN&(~getForcedWindowFlags()));
  10. }
  11. ...
  12. WindowManager.LayoutParams params = getAttributes();
  13. ...
  14. mDecor.startChanging();
  15. //根据窗口主题风格选择不同的布局文件layoutResource
  16. ...
  17. //加载布局文件
  18. ①View in = mLayoutInflater.inflate(layoutResource, null);
  19. //添加到DecorView中
  20. ②decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
  21. //从窗口视图中找出窗口内容视图对象
  22. ③ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
  23. ...
  24. mDecor.finishChanging();
  25. return contentParent;
  26. }

到此Activity的所有视图对象都已经创建完毕,DecorView是Activity的顶级视图,由窗口PhoneWindow对象持有,在DecorView视图对象中添加了一个ViewGroup容器组件contentParent,所有用户定义视图组件将被添加到该容器中。

handleResumeActivity

performLaunchActivity函数完成了两件事:

1)        Activity窗口对象的创建,通过attach函数来完成;

2)        Activity视图对象的创建,通过setContentView函数来完成;

这些准备工作完成后,就可以显示该Activity了,应用程序进程通过调用handleResumeActivity函数来启动Activity的显示过程。

frameworks\base\core\java\android\app\ ActivityThread.java


 
 
  1. final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
  2. unscheduleGcIdler();
  3. ActivityClientRecord r;
  4. try {
  5. ①r = performResumeActivity(token, clearHide);
  6. } catch (Exception e) {
  7. ...
  8. }
  9. if (r != null) {
  10. final Activity a = r.activity;
  11. ...
  12. if (r.window == null && !a.mFinished && willBeVisible) {
  13. //获得为当前Activity创建的窗口PhoneWindow对象
  14. r.window = r.activity.getWindow();
  15. //获取为窗口创建的视图DecorView对象
  16. View decor = r.window.getDecorView();
  17. decor.setVisibility(View.INVISIBLE);
  18. //在attach函数中就为当前Activity创建了WindowManager对象
  19. ViewManager wm = a.getWindowManager();
  20. //得到该视图对象的布局参数
  21. ②WindowManager.LayoutParams l = r.window.getAttributes();
  22. //将视图对象保存到Activity的成员变量mDecor中
  23. a.mDecor = decor;
  24. l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
  25. if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
  26. l.idleScreenAvailable = true;
  27. } else {
  28. l.idleScreenAvailable = false;
  29. }
  30. l.softInputMode |= forwardBit;
  31. if (a.mVisibleFromClient) {
  32. a.mWindowAdded = true;
  33. //将创建的视图对象DecorView添加到Activity的窗口管理器中
  34. ③wm.addView(decor, l);
  35. }
  36. } else if (!willBeVisible) {
  37. ...
  38. }
  39. ...
  40. if (!r.onlyLocalRequest) {
  41. r.nextIdle = mNewActivities;
  42. mNewActivities = r;
  43. Looper.myQueue().addIdleHandler( new Idler());
  44. }
  45. ...
  46. } else {
  47. ...
  48. }
  49. }

我们知道,在前面的performLaunchActivity函数中完成Activity的创建后,会将当前当前创建的Activity在应用程序进程端的描述符ActivityClientRecord以键值对的形式保存到ActivityThread的成员变量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份证,即是IApplicationToken.Proxy代理对象,也用于与AMS通信。上面的函数首先通过performResumeActivity从mActivities变量中取出Activity的应用程序端描述符ActivityClientRecord,然后取出前面为Activity创建的视图对象DecorView和窗口管理器WindowManager,最后将视图对象添加到窗口管理器中。


我们知道Activity引用的其实是轻量级的窗口管理器LocalWindowManager

frameworks\base\core\java\android\view\ Window.java


 
 
  1. public final void addView(View view, ViewGroup.LayoutParams params) {
  2. WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
  3. CharSequence curTitle = wp.getTitle();
  4. //应用程序窗口
  5. if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
  6. wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
  7. if (wp.token == null) {
  8. View decor = peekDecorView();
  9. if (decor != null) {
  10. // LayoutParams 的token设置为W本地Binder对象
  11. wp.token = decor.getWindowToken();
  12. }
  13. }
  14. if (curTitle == null || curTitle.length() == 0) {
  15. //根据窗口类型设置不同的标题
  16. if (mAppName != null) {
  17. title += ":" + mAppName;
  18. }
  19. wp.setTitle(title);
  20. }
  21. } else { //系统窗口
  22. if (wp.token == null) {
  23. wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
  24. }
  25. if ((curTitle == null || curTitle.length() == 0)
  26. && mAppName != null) {
  27. wp.setTitle(mAppName);
  28. }
  29. }
  30. if (wp.packageName == null) {
  31. wp.packageName = mContext.getPackageName();
  32. }
  33. if (mHardwareAccelerated) {
  34. wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
  35. }
  36. super.addView(view, params);
  37. }

LocalWindowManager的addView函数对不同类型窗口的布局参数进行相应的设置,比如布局参数中的token设置,如果是应用程序窗口,则设置token为W本地Binder对象。如果不是应用程序窗口,同时当前窗口没有父窗口,则设置token为当前窗口的IApplicationToken.Proxy代理对象,否则设置为父窗口的IApplicationToken.Proxy代理对象。最后视图组件的添加工作交给其父类来完成。LocalWindowManager继承于CompatModeWrapper,是WindowManagerImpl的内部类。

frameworks\base\core\java\android\view\WindowManagerImpl.java


 
 
  1. public void addView(View view, android.view.ViewGroup.LayoutParams params) {
  2. mWindowManager.addView(view, params, mCompatibilityInfo);
  3. }

前面我们介绍了,每一个Activity拥有一个轻量级窗口管理器,通过轻量级窗口管理器LocalWindowManager来访问重量级窗口管理器WindowManagerImpl,因此视图组件的添加过程又转交给了WindowManagerImpl来实现。


 
 
  1. public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
  2. addView(view, params, cih, false);
  3. }

该函数又调用WindowManagerImpl的另一个重载函数来添加视图组件


 
 
  1. private void addView(View view, ViewGroup.LayoutParams params,
  2. CompatibilityInfoHolder cih, boolean nest) {
  3. ...
  4. final WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;
  5. ViewRootImpl root;
  6. View panelParentView = null;
  7. synchronized ( this) {
  8. ...
  9. //从mViews中查找当前添加的View
  10. int index = findViewLocked(view, false);
  11. //如果已经存在,直接返回
  12. if (index >= 0) {
  13. ...
  14. return;
  15. }
  16. //尚未添加当前View
  17. if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
  18. wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
  19. final int count = mViews != null ? mViews.length : 0;
  20. for ( int i= 0; i<count; i++) {
  21. if (mRoots[i].mWindow.asBinder() == wparams.token) {
  22. panelParentView = mViews[i];
  23. }
  24. }
  25. }
  26. //为Activity创建一个ViewRootImpl对象
  27. ①root = new ViewRootImpl(view.getContext());
  28. ...
  29. //设置视图组件的布局参数
  30. view.setLayoutParams(wparams);
  31. if (mViews == null) {
  32. index = 1;
  33. mViews = new View[ 1];
  34. mRoots = new ViewRootImpl[ 1];
  35. mParams = new WindowManager.LayoutParams[ 1];
  36. } else {
  37. //动态增加mViews数组长度
  38. index = mViews.length + 1;
  39. Object[] old = mViews;
  40. mViews = new View[index];
  41. System.arraycopy(old, 0, mViews, 0, index- 1);
  42. //动态增加mRoots数组长度
  43. old = mRoots;
  44. mRoots = new ViewRootImpl[index];
  45. System.arraycopy(old, 0, mRoots, 0, index- 1);
  46. //动态增加mParams数组长度
  47. old = mParams;
  48. mParams = new WindowManager.LayoutParams[index];
  49. System.arraycopy(old, 0, mParams, 0, index- 1);
  50. }
  51. index--;
  52. ②mViews[index] = view;
  53. mRoots[index] = root;
  54. mParams[index] = wparams;
  55. }
  56. try {
  57. ③root.setView(view, wparams, panelParentView);
  58. } catch (RuntimeException e) {
  59. ...
  60. }
  61. }

到此我们知道,当应用程序向窗口管理器中添加一个视图对象时,首先会为该视图对象创建一个ViewRootImpl对象,并且将视图对象、ViewRootImpl对象、视图布局参数分别保存到窗口管理器WindowManagerImpl得mViews、mRoots、mParams数组中,如下图所示:



最后通过ViewRootImpl对象来完成视图的显示过程。

ViewRootImpl构造过程

frameworks\base\core\java\android\view\ViewRootImpl.java


 
 
  1. public ViewRootImpl(Context context) {
  2. ...
  3. ①getWindowSession(context.getMainLooper());
  4. mThread = Thread.currentThread();
  5. mLocation = new WindowLeaked( null);
  6. mLocation.fillInStackTrace();
  7. mWidth = - 1;
  8. mHeight = - 1;
  9. mDirty = new Rect();
  10. mTempRect = new Rect();
  11. mVisRect = new Rect();
  12. mWinFrame = new Rect();
  13. ②mWindow = new W( this);
  14. mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
  15. mInputMethodCallback = new InputMethodCallback( this);
  16. mViewVisibility = View.GONE;
  17. mTransparentRegion = new Region();
  18. mPreviousTransparentRegion = new Region();
  19. mFirst = true; // true for the first time the view is added
  20. mAdded = false;
  21. mAccessibilityManager = AccessibilityManager.getInstance(context);
  22. mAccessibilityInteractionConnectionManager =
  23. new AccessibilityInteractionConnectionManager();
  24. mAccessibilityManager.addAccessibilityStateChangeListener(
  25. mAccessibilityInteractionConnectionManager);
  26. ③mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this);
  27. mViewConfiguration = ViewConfiguration.get(context);
  28. mDensity = context.getResources().getDisplayMetrics().densityDpi;
  29. mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
  30. mProfileRendering = Boolean.parseBoolean(
  31. SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
  32. ④mChoreographer = Choreographer.getInstance();
  33. PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
  34. mAttachInfo.mScreenOn = powerManager.isScreenOn();
  35. loadSystemProperties();
  36. }

在ViewRootImpl的构造函数中初始化了一些成员变量,ViewRootImpl创建了以下几个主要对象:

1)        通过getWindowSession(context.getMainLooper())得到IWindowSession的代理对象,该对象用于和WMS通信。

2)        创建了一个W本地Binder对象,用于WMS通知应用程序进程。

3)        采用单例模式创建了一个Choreographer对象,用于统一调度窗口绘图。

4)        创建ViewRootHandler对象,用于处理当前视图消息。

5)        构造一个AttachInfo对象;

6)        创建Surface对象,用于绘制当前视图,当然该Surface对象的真正创建是由WMS来完成的,只不过是WMS传递给应用程序进程的。


 
 
  1. private final Surface mSurface = new Surface();
  2. final ViewRootHandler mHandler = new ViewRootHandler();


IWindowSession代理获取过程

frameworks\base\core\java\android\view\ViewRootImpl.java


 
 
  1. public static IWindowSession getWindowSession(Looper mainLooper) {
  2. synchronized (mStaticInit) {
  3. if (!mInitialized) {
  4. try {
  5. //获取输入法管理器
  6. InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
  7. //获取窗口管理器
  8. IWindowManager windowManager = Display.getWindowManager();
  9. //得到IWindowSession代理对象
  10. sWindowSession = windowManager.openSession(imm.getClient(), imm.getInputContext());
  11. float animatorScale = windowManager.getAnimationScale( 2);
  12. ValueAnimator.setDurationScale(animatorScale);
  13. mInitialized = true;
  14. } catch (RemoteException e) {
  15. }
  16. }
  17. return sWindowSession;
  18. }
  19. }

以上函数通过WMS的openSession函数创建应用程序与WMS之间的连接通道,即获取IWindowSession代理对象,并将该代理对象保存到ViewRootImpl的静态成员变量sWindowSession中

static IWindowSession sWindowSession;
 
 

因此在应用程序进程中有且只有一个IWindowSession代理对象。

frameworks\base\services\java\com\android\server\wm\WindowManagerService.java


 
 
  1. public IWindowSession openSession(IInputMethodClient client,
  2. IInputContext inputContext) {
  3. if (client == null) throw new IllegalArgumentException( "null client");
  4. if (inputContext == null) throw new IllegalArgumentException( "null inputContext");
  5. Session session = new Session( this, client, inputContext);
  6. return session;
  7. }

在WMS服务端构造了一个Session实例对象。


AttachInfo构造过程

frameworks\base\core\java\android\view\ View.java


 
 
  1. AttachInfo(IWindowSession session, IWindow window,
  2. ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
  3. mSession = session; //IWindowSession代理对象,用于与WMS通信
  4. mWindow = window; //W对象
  5. mWindowToken = window.asBinder(); //W本地Binder对象
  6. mViewRootImpl = viewRootImpl; //ViewRootImpl实例
  7. mHandler = handler; //ViewRootHandler对象
  8. mRootCallbacks = effectPlayer; //ViewRootImpl实例
  9. }


创建Choreographer对象

Android Project Butter分析中介绍了Android4.1引入VSYNC、Triple Buffer和Choreographer来改善Android先天存在的UI流畅性差问题,有关Choreographer的实现过程请参看Android系统Choreographer机制实现过程

视图View添加过程

窗口管理器WindowManagerImpl为当前添加的窗口创建好各种对象后,调用ViewRootImpl的setView函数向WMS服务添加一个窗口对象。


 
 
  1. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  2. synchronized ( this) {
  3. if (mView == null) {
  4. //将DecorView保存到ViewRootImpl的成员变量mView中
  5. mView = view;
  6. mFallbackEventHandler.setView(view);
  7. mWindowAttributes.copyFrom(attrs);
  8. attrs = mWindowAttributes;
  9. mClientWindowLayoutFlags = attrs.flags;
  10. setAccessibilityFocus( null, null);
  11. //DecorView实现了RootViewSurfaceTaker接口
  12. if (view instanceof RootViewSurfaceTaker) {
  13. mSurfaceHolderCallback =
  14. ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
  15. if (mSurfaceHolderCallback != null) {
  16. mSurfaceHolder = new TakenSurfaceHolder();
  17. mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
  18. }
  19. }
  20. ...
  21. //同时将DecorView保存到mAttachInfo中
  22. mAttachInfo.mRootView = view;
  23. mAttachInfo.mScalingRequired = mTranslator != null;
  24. mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
  25. if (panelParentView != null) {
  26. mAttachInfo.mPanelParentWindowToken
  27. = panelParentView.getApplicationWindowToken();
  28. }
  29. ...
  30. //在添加窗口前进行UI布局
  31. ①requestLayout();
  32. if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
  33. mInputChannel = new InputChannel();
  34. }
  35. try {
  36. mOrigWindowType = mWindowAttributes.type;
  37. mAttachInfo.mRecomputeGlobalAttributes = true;
  38. collectViewAttributes();
  39. //将窗口添加到WMS服务中,mWindow为W本地Binder对象,通过Binder传输到WMS服务端后,变为IWindow代理对象
  40. ②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
  41. getHostVisibility(), mAttachInfo.mContentInsets,
  42. mInputChannel);
  43. } catch (RemoteException e) {
  44. ...
  45. }
  46. ...
  47. //建立窗口消息通道
  48. if (view instanceof RootViewSurfaceTaker) {
  49. mInputQueueCallback =
  50. ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
  51. }
  52. if (mInputChannel != null) {
  53. if (mInputQueueCallback != null) {
  54. mInputQueue = new InputQueue(mInputChannel);
  55. mInputQueueCallback.onInputQueueCreated(mInputQueue);
  56. } else {
  57. mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
  58. }
  59. }
  60. ...
  61. }
  62. }
  63. }

通过前面的分析可以知道,用户自定义的UI作为一个子View被添加到DecorView中,然后将顶级视图DecorView添加到应用程序进程的窗口管理器中,窗口管理器首先为当前添加的View创建一个ViewRootImpl对象、一个布局参数对象ViewGroup.LayoutParams,然后将这三个对象分别保存到当前应用程序进程的窗口管理器WindowManagerImpl中,最后通过ViewRootImpl对象将当前视图对象注册到WMS服务中。

ViewRootImpl的setView函数向WMS服务添加一个窗口对象过程:

1)         requestLayout()在应用程序进程中进行窗口UI布局;

2)         WindowSession.add()向WMS服务注册一个窗口对象;

3)         注册应用程序进程端的消息接收通道;

窗口UI布局过程

frameworks\base\core\java\android\view\ViewRootImpl.java


 
 
  1. public void requestLayout() {
  2. //检查当前线程是否是UI线程
  3. checkThread();
  4. //标识当前正在请求UI布局
  5. mLayoutRequested = true;
  6. scheduleTraversals();
  7. }

窗口布局过程必须在UI线程中进行,因此该函数首先检查调用requestLayout()函数的线程是否为创建ViewRootImpl对象的线程。然后调用scheduleTraversals()函数启动Choreographer的Callback遍历过程。


 
 
  1. void scheduleTraversals() {
  2. if (!mTraversalScheduled) {
  3. mTraversalScheduled = true;
  4. //暂停UI线程消息队列对同步消息的处理
  5. mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
  6. //向Choreographer注册一个类型为CALLBACK_TRAVERSAL的回调,用于处理UI绘制
  7. mChoreographer.postCallback(
  8. Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
  9. //向Choreographer注册一个类型为CALLBACK_INPUT的回调,用于处理输入事件
  10. scheduleConsumeBatchedInput();
  11. }
  12. }

关于Choreographer的postCallback()用法在前面进行了详细的介绍,当Vsync事件到来时,mTraversalRunnable对象的run()函数将被调用。

frameworks\base\core\java\android\view\ViewRootImpl.java


 
 
  1. final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
  2. final class TraversalRunnable implements Runnable {
  3. @Override
  4. public void run() {
  5. doTraversal();
  6. }
  7. }

mTraversalRunnable对象的类型为TraversalRunnable,该类实现了Runnable接口,在其run()函数中调用了doTraversal()函数来完成窗口布局。


 
 
  1. void doTraversal() {
  2. if (mTraversalScheduled) {
  3. mTraversalScheduled = false;
  4. mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
  5. if (mProfile) {
  6. Debug.startMethodTracing( "ViewAncestor");
  7. }
  8. Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
  9. try {
  10. performTraversals();
  11. } finally {
  12. Trace.traceEnd(Trace.TRACE_TAG_VIEW);
  13. }
  14. if (mProfile) {
  15. Debug.stopMethodTracing();
  16. mProfile = false;
  17. }
  18. }
  19. }

performTraversals函数相当复杂,其主要实现以下几个重要步骤:

1.执行窗口测量;

2.执行窗口注册;

3.执行窗口布局;

4.执行窗口绘图;


 
 
  1. private void performTraversals() {
  2. // cache mView since it is used so much below...
  3. final View host = mView;
  4. if (host == null || !mAdded)
  5. return;
  6. mWillDrawSoon = true;
  7. boolean windowSizeMayChange = false;
  8. boolean newSurface = false;
  9. boolean surfaceChanged = false;
  10. WindowManager.LayoutParams lp = mWindowAttributes;
  11. int desiredWindowWidth;
  12. int desiredWindowHeight;
  13. final View.AttachInfo attachInfo = mAttachInfo;
  14. final int viewVisibility = getHostVisibility();
  15. boolean viewVisibilityChanged = mViewVisibility != viewVisibility
  16. || mNewSurfaceNeeded;
  17. WindowManager.LayoutParams params = null;
  18. if (mWindowAttributesChanged) {
  19. mWindowAttributesChanged = false;
  20. surfaceChanged = true;
  21. params = lp;
  22. }
  23. ...
  24. /****************执行窗口测量******************/
  25. boolean layoutRequested = mLayoutRequested && !mStopped;
  26. if (layoutRequested) {
  27. ...
  28. // Ask host how big it wants to be
  29. windowSizeMayChange |= measureHierarchy(host, lp, res,
  30. desiredWindowWidth, desiredWindowHeight);
  31. }
  32. ...
  33. /****************向WMS服务添加窗口******************/
  34. if (mFirst || windowShouldResize || insetsChanged ||
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值