Android应用程序窗口设计框架 一

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

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

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

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

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

\

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

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

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

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

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

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

performLaunchActivity

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

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

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

在该函数中,首先通过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
2
3
4
5
6
public Activity newActivity(ClassLoader cl, String className,
         Intent intent)
         throws InstantiationException, IllegalAccessException,
         ClassNotFoundException {
     return (Activity)cl.loadClass(className).newInstance();
}

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

LoadedApk构造过程

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

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

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


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


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

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

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

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

Application构造过程

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

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

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

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

ContextImpl构造过程

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

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

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

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

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

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

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

\

对象Attach过程

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

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

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

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

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

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

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

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

parent:启动当前Activity的Activity;

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

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

1) 将Activity设置到FragmentManager中;

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

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

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

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

\

应用程序窗口创建过程

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

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

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

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

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

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

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

?
1
2
3
4
5
6
7
8
9
private static final String[] preload_classes = {
     "com.android.internal.policy.impl.PhoneLayoutInflater" ,
     "com.android.internal.policy.impl.PhoneWindow" ,
     "com.android.internal.policy.impl.PhoneWindow$1" ,
     "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback" ,
     "com.android.internal.policy.impl.PhoneWindow$DecorView" ,
     "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState" ,
     "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState" ,
};
?
1
2
3
4
5
6
7
8
9
static {
     for (String s : preload_classes) {
         try {
             Class.forName(s);
         } catch (ClassNotFoundException ex) {
             Log.e(TAG, "Could not preload class for phone policy: " + s);
         }
     }
}

PhoneWindow的构造过程

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

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

窗口管理器创建过程

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

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

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

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

\

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

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

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

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

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

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

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

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

\

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

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

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

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

frameworks\base\core\jni\android_view_Display.cpp

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

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

frameworks\native\libs\gui\ SurfaceComposerClient.cpp

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

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

\

Activity视图对象的创建过程

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

\

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

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

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

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

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

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

\

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


猜你喜欢

转载自blog.csdn.net/linghu_java/article/details/42964585