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

在Android系统中,一个Activity相应一个应用程序窗体。不论什么一个Activity的启动都是由AMS服务和应用程序进程相互配合来完毕的。AMS服务统一调度系统中全部进程的Activity启动,而每一个Activity的启动过程则由其所属进程来完毕。AMS服务通过realStartActivityLocked函数来通知应用程序进程启动某个Activity:

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

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

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);
}

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

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

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

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

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

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类

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

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;
}
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);
}
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;
	}
}

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

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

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

ContextImpl() {
	mOuterContext = this;
}

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

final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread) {
	init(packageInfo, activityToken, mainThread, null, null);
}
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

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。

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

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

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

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

public Window makeNewWindow(Context context) {
	return new PhoneWindow(context);
}

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

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",
};
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的构造过程

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

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

private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
public static WindowManagerImpl getDefault() {
	return sWindowManager;
}

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

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

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

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;
}

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

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

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

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的初始化过程非常easy,就是通过SurfaceComposerClient请求SurfaceFlinger得到显示屏的基本信息。

frameworks\native\libs\gui\ SurfaceComposerClient.cpp

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

public void callActivityOnCreate(Activity activity, Bundle icicle) {
	...
	activity.performCreate(icicle);
	...
}

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

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

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

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

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

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对象

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

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

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,全部用户定义视图组件将被加入到该容器中。

handleResumeActivity

performLaunchActivity函数完毕了两件事:

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

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

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

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

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
	unscheduleGcIdler();
	ActivityClientRecord r;
	try {
		①r = performResumeActivity(token, clearHide);
	} catch (Exception e) {
		...
	}
	if (r != null) {
		final Activity a = r.activity;
		...
		if (r.window == null && !a.mFinished && willBeVisible) {
			//获得为当前Activity创建的窗体PhoneWindow对象
			r.window = r.activity.getWindow();
			//获取为窗体创建的视图DecorView对象
			View decor = r.window.getDecorView();
			decor.setVisibility(View.INVISIBLE);
			//在attach函数中就为当前Activity创建了WindowManager对象
			ViewManager wm = a.getWindowManager();
			//得到该视图对象的布局參数
			②WindowManager.LayoutParams l = r.window.getAttributes();
			//将视图对象保存到Activity的成员变量mDecor中
			a.mDecor = decor;
			l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
			if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
				l.idleScreenAvailable = true;
			} else {
				l.idleScreenAvailable = false;
			}
			l.softInputMode |= forwardBit;
			if (a.mVisibleFromClient) {
				a.mWindowAdded = true;
				//将创建的视图对象DecorView加入到Activity的窗体管理器中
				③wm.addView(decor, l);
			}
		} else if (!willBeVisible) {
			...
		}
		...
		if (!r.onlyLocalRequest) {
			r.nextIdle = mNewActivities;
			mNewActivities = r;
			Looper.myQueue().addIdleHandler(new Idler());
		}
		...
	} else {
		...
	}
}

我们知道,在前面的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

public final void addView(View view, ViewGroup.LayoutParams params) {
	WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
	CharSequence curTitle = wp.getTitle();
	//应用程序窗体
	if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
		wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
		if (wp.token == null) {
			View decor = peekDecorView();
			if (decor != null) {
				// LayoutParams 的token设置为W本地Binder对象
				wp.token = decor.getWindowToken();
			}
		}
		if (curTitle == null || curTitle.length() == 0) {
			//依据窗体类型设置不同的标题
			…
			if (mAppName != null) {
				title += ":" + mAppName;
			}
			wp.setTitle(title);
		}
	} else {//系统窗体
		if (wp.token == null) {
			wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
		}
		if ((curTitle == null || curTitle.length() == 0)
				&& mAppName != null) {
			wp.setTitle(mAppName);
		}
    }
	if (wp.packageName == null) {
		wp.packageName = mContext.getPackageName();
	}
	if (mHardwareAccelerated) {
		wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
	}
	super.addView(view, params);
}

LocalWindowManager的addView函数对不同类型窗体的布局參数进行对应的设置,比方布局參数中的token设置,假设是应用程序窗体,则设置token为W本地Binder对象。假设不是应用程序窗体。同一时候当前窗体没有父窗体。则设置token为当前窗体的IApplicationToken.Proxy代理对象,否则设置为父窗体的IApplicationToken.Proxy代理对象。最后视图组件的加入工作交给其父类来完毕。

LocalWindowManager继承于CompatModeWrapper,是WindowManagerImpl的内部类。

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

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

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

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

该函数又调用WindowManagerImpl的还有一个重载函数来加入视图组件

private void addView(View view, ViewGroup.LayoutParams params,
		CompatibilityInfoHolder cih, boolean nest) {
	...
	final WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;
	ViewRootImpl root;
	View panelParentView = null;
	synchronized (this) {
		...
		//从mViews中查找当前加入的View
		int index = findViewLocked(view, false);
		//假设已经存在,直接返回
		if (index >= 0) {
			...
			return;
		}
		//尚未加入当前View
		if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
				wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
			final int count = mViews != null ? mViews.length : 0;
			for (int i=0; i<count; i++) {
				if (mRoots[i].mWindow.asBinder() == wparams.token) {
					panelParentView = mViews[i];
				}
			}
		}
		//为Activity创建一个ViewRootImpl对象
		①root = new ViewRootImpl(view.getContext());
		...
		//设置视图组件的布局參数
		view.setLayoutParams(wparams);
		if (mViews == null) {
			index = 1;
			mViews = new View[1];
			mRoots = new ViewRootImpl[1];
			mParams = new WindowManager.LayoutParams[1];
		} else {
			//动态添加mViews数组长度
			index = mViews.length + 1;
			Object[] old = mViews;
			mViews = new View[index];
			System.arraycopy(old, 0, mViews, 0, index-1);
			//动态添加mRoots数组长度
			old = mRoots;
			mRoots = new ViewRootImpl[index];
			System.arraycopy(old, 0, mRoots, 0, index-1);
			//动态添加mParams数组长度
			old = mParams;
			mParams = new WindowManager.LayoutParams[index];
			System.arraycopy(old, 0, mParams, 0, index-1);
		}
		index--;
		②mViews[index] = view;
		mRoots[index] = root;
		mParams[index] = wparams;
	}
	try {
		③root.setView(view, wparams, panelParentView);
	} catch (RuntimeException e) {
		...
	}
}

到此我们知道,当应用程序向窗体管理器中加入一个视图对象时,首先会为该视图对象创建一个ViewRootImpl对象。而且将视图对象、ViewRootImpl对象、视图布局參数分别保存到窗体管理器WindowManagerImpl得mViews、mRoots、mParams数组中,例如以下图所看到的:

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

ViewRootImpl构造过程

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

public ViewRootImpl(Context context) {
	...
	①getWindowSession(context.getMainLooper());
	mThread = Thread.currentThread();
	mLocation = new WindowLeaked(null);
	mLocation.fillInStackTrace();
	mWidth = -1;
	mHeight = -1;
	mDirty = new Rect();
	mTempRect = new Rect();
	mVisRect = new Rect();
	mWinFrame = new Rect();
	②mWindow = new W(this);
	mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
	mInputMethodCallback = new InputMethodCallback(this);
	mViewVisibility = View.GONE;
	mTransparentRegion = new Region();
	mPreviousTransparentRegion = new Region();
	mFirst = true; // true for the first time the view is added
	mAdded = false;
	mAccessibilityManager = AccessibilityManager.getInstance(context);
	mAccessibilityInteractionConnectionManager =
		new AccessibilityInteractionConnectionManager();
	mAccessibilityManager.addAccessibilityStateChangeListener(
			mAccessibilityInteractionConnectionManager);
	③mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this);
	mViewConfiguration = ViewConfiguration.get(context);
	mDensity = context.getResources().getDisplayMetrics().densityDpi;
	mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
	mProfileRendering = Boolean.parseBoolean(
			SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
	④mChoreographer = Choreographer.getInstance();
	PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
	mAttachInfo.mScreenOn = powerManager.isScreenOn();
	loadSystemProperties();
}

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

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

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

3)        採用单例模式创建了一个Choreographer对象,用于统一调度窗体画图。

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

5)        构造一个AttachInfo对象;

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

private final Surface mSurface = new Surface();
final ViewRootHandler mHandler = new ViewRootHandler();

IWindowSession代理获取过程

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

public static IWindowSession getWindowSession(Looper mainLooper) {
	synchronized (mStaticInit) {
		if (!mInitialized) {
			try {
				//获取输入法管理器
				InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
				//获取窗体管理器
				IWindowManager windowManager = Display.getWindowManager();
				//得到IWindowSession代理对象
				sWindowSession = windowManager.openSession(imm.getClient(), imm.getInputContext());
				float animatorScale = windowManager.getAnimationScale(2);
				ValueAnimator.setDurationScale(animatorScale);
				mInitialized = true;
			} catch (RemoteException e) {
			}
		}
		return sWindowSession;
	}
}

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

static IWindowSession sWindowSession;

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

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

public IWindowSession openSession(IInputMethodClient client,
		IInputContext inputContext) {
	if (client == null) throw new IllegalArgumentException("null client");
	if (inputContext == null) throw new IllegalArgumentException("null inputContext");
	Session session = new Session(this, client, inputContext);
	return session;
}

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

AttachInfo构造过程

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

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

创建Choreographer对象

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

视图View加入过程

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

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	synchronized (this) {
		if (mView == null) {
			//将DecorView保存到ViewRootImpl的成员变量mView中
			mView = view;
			mFallbackEventHandler.setView(view);
			mWindowAttributes.copyFrom(attrs);
			attrs = mWindowAttributes;
			mClientWindowLayoutFlags = attrs.flags;
            setAccessibilityFocus(null, null);
			//DecorView实现了RootViewSurfaceTaker接口
			if (view instanceof RootViewSurfaceTaker) {
				mSurfaceHolderCallback =
						((RootViewSurfaceTaker)view).willYouTakeTheSurface();
				if (mSurfaceHolderCallback != null) {
					mSurfaceHolder = new TakenSurfaceHolder();
					mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
				}
			}
			...
			//同一时候将DecorView保存到mAttachInfo中
			mAttachInfo.mRootView = view;
			mAttachInfo.mScalingRequired = mTranslator != null;
			mAttachInfo.mApplicationScale = mTranslator == null ?

1.0f : mTranslator.applicationScale;
			if (panelParentView != null) {
				mAttachInfo.mPanelParentWindowToken
						= panelParentView.getApplicationWindowToken();
			}
			...
			//在加入窗体前进行UI布局
			①requestLayout();
			if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
				mInputChannel = new InputChannel();
			}
			try {
				mOrigWindowType = mWindowAttributes.type;
				mAttachInfo.mRecomputeGlobalAttributes = true;
				collectViewAttributes();
				//将窗体加入到WMS服务中,mWindow为W本地Binder对象,通过Binder传输到WMS服务端后。变为IWindow代理对象
				②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
						getHostVisibility(), mAttachInfo.mContentInsets,
						mInputChannel);
			} catch (RemoteException e) {
				...
			}
			...
			//建立窗体消息通道
			if (view instanceof RootViewSurfaceTaker) {
				mInputQueueCallback =
					((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
			}
			if (mInputChannel != null) {
				if (mInputQueueCallback != null) {
					mInputQueue = new InputQueue(mInputChannel);
					mInputQueueCallback.onInputQueueCreated(mInputQueue);
				} else {
					mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
				}
			}
			...
		}
	}
}

通过前面的分析能够知道,用户自己定义的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

public void requestLayout() {
	//检查当前线程是否是UI线程
	checkThread();
	//标识当前正在请求UI布局
	mLayoutRequested = true;
	scheduleTraversals();
}

窗体布局过程必须在UI线程中进行。因此该函数首先检查调用requestLayout()函数的线程是否为创建ViewRootImpl对象的线程。

然后调用scheduleTraversals()函数启动Choreographer的Callback遍历过程。

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

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

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

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
}

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

void doTraversal() {
	if (mTraversalScheduled) {
		mTraversalScheduled = false;
		mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
		if (mProfile) {
			Debug.startMethodTracing("ViewAncestor");
		}
		Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
		try {
			performTraversals();
		} finally {
			Trace.traceEnd(Trace.TRACE_TAG_VIEW);
		}
		if (mProfile) {
			Debug.stopMethodTracing();
			mProfile = false;
		}
	}
}

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

1.运行窗体測量;

2.运行窗体注冊;

3.运行窗体布局。

4.运行窗体画图;

private void performTraversals() {
	// cache mView since it is used so much below...
	final View host = mView;
	if (host == null || !mAdded)
		return;
	mWillDrawSoon = true;
	boolean windowSizeMayChange = false;
	boolean newSurface = false;
	boolean surfaceChanged = false;
	WindowManager.LayoutParams lp = mWindowAttributes;
	int desiredWindowWidth;
	int desiredWindowHeight;
	final View.AttachInfo attachInfo = mAttachInfo;
	final int viewVisibility = getHostVisibility();
	boolean viewVisibilityChanged = mViewVisibility != viewVisibility
			|| mNewSurfaceNeeded;
	WindowManager.LayoutParams params = null;
	if (mWindowAttributesChanged) {
		mWindowAttributesChanged = false;
		surfaceChanged = true;
		params = lp;
	}
	...
	/****************运行窗体測量******************/
	boolean layoutRequested = mLayoutRequested && !mStopped;
	if (layoutRequested) {
		...
		// Ask host how big it wants to be
		windowSizeMayChange |= measureHierarchy(host, lp, res,
				desiredWindowWidth, desiredWindowHeight);
	}
	...
	/****************向WMS服务加入窗体******************/
	if (mFirst || windowShouldResize || insetsChanged ||
			viewVisibilityChanged || params != null) {
		...
		try {
			final int surfaceGenerationId = mSurface.getGenerationId();
			relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
			...
		} catch (RemoteException e) {
		}
		...
		if (!mStopped) {
			boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
					(relayoutResult&WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
			if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
					|| mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
				...
				 // Ask host how big it wants to be
				performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
				...
			}
		}
	}
	/****************运行窗体布局******************/
	final boolean didLayout = layoutRequested && !mStopped;
	boolean triggerGlobalLayoutListener = didLayout
			|| attachInfo.mRecomputeGlobalAttributes;
	if (didLayout) {
		performLayout();
		...
	}
	...
	/****************查找窗体焦点******************/
	boolean skipDraw = false;
	if (mFirst) {
		// handle first focus request
		if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
				+ mView.hasFocus());
		if (mView != null) {
			if (!mView.hasFocus()) {
				mView.requestFocus(View.FOCUS_FORWARD);
				mFocusedView = mRealFocusedView = mView.findFocus();
				if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
						+ mFocusedView);
			} else {
				mRealFocusedView = mView.findFocus();
				if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
						+ mRealFocusedView);
			}
		}
		if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_ANIMATING) != 0) {
			// The first time we relayout the window, if the system is
			// doing window animations, we want to hold of on any future
			// draws until the animation is done.
			mWindowsAnimating = true;
		}
	} else if (mWindowsAnimating) {
		skipDraw = true;
	}
	/****************运行窗体绘制******************/
	mFirst = false;
	mWillDrawSoon = false;
	mNewSurfaceNeeded = false;
	mViewVisibility = viewVisibility;
	...
	boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
			viewVisibility != View.VISIBLE;
	if (!cancelDraw && !newSurface) {
		if (!skipDraw || mReportNextDraw) {
			if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
				for (int i = 0; i < mPendingTransitions.size(); ++i) {
					mPendingTransitions.get(i).startChangingAnimations();
				}
				mPendingTransitions.clear();
			}
			performDraw();
		}
	} else {
		if (viewVisibility == View.VISIBLE) {
			// Try again
			scheduleTraversals();
		} else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
			for (int i = 0; i < mPendingTransitions.size(); ++i) {
				mPendingTransitions.get(i).endChangingAnimations();
			}
			mPendingTransitions.clear();
		}
	}
}
performMeasure

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

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
 try {
  mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
 } finally {
  Trace.traceEnd(Trace.TRACE_TAG_VIEW);
 }
}
relayoutWindow

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

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
		boolean insetsPending) throws RemoteException {
	...
	int relayoutResult = sWindowSession.relayout(
			mWindow, mSeq, params,
			(int) (mView.getMeasuredWidth() * appScale + 0.5f),
			(int) (mView.getMeasuredHeight() * appScale + 0.5f),
			viewVisibility, insetsPending ? WindowManagerImpl.RELAYOUT_INSETS_PENDING : 0,
			mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
			mPendingConfiguration, mSurface);
	...
	return relayoutResult;
}

这里通过前面获取的IWindowSession代理对象请求WMS服务运行窗体布局,mSurface是ViewRootImpl的成员变量

private final Surface mSurface = new Surface();

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

public Surface() {
	checkHeadless();
	if (DEBUG_RELEASE) {
		mCreationStack = new Exception();
	}
	mCanvas = new CompatibleCanvas();
}

该Surface构造函数只创建了一个CompatibleCanvas对象,并没有对该Surface进程native层的初始化,到此我们知道应用程序进程为每一个窗体对象都创建了一个Surface对象。

而且将该Surface通过跨进程方式传输给WMS服务进程,我们知道,在Android系统中。假设一个对象须要在不同进程间传输,必须实现Parcelable接口,Surface类正好实现了Parcelable接口。ViewRootImpl通过IWindowSession接口请求WMS的完整步骤例如以下:

frameworks\base\core\java\android\view\IWindowSession.java$ Proxy

public int relayout(android.view.IWindow window, int seq,
		android.view.WindowManager.LayoutParams attrs, int requestedWidth,
		int requestedHeight, int viewVisibility, int flags,
		android.graphics.Rect outFrame,
		android.graphics.Rect outOverscanInsets,
		android.graphics.Rect outContentInsets,
		android.graphics.Rect outVisibleInsets,
		android.content.res.Configuration outConfig,
		android.view.Surface outSurface) throws android.os.RemoteException {
	android.os.Parcel _data = android.os.Parcel.obtain();
	android.os.Parcel _reply = android.os.Parcel.obtain();
	int _result;
	try {
		_data.writeInterfaceToken(DESCRIPTOR);
		_data.writeStrongBinder((((window != null)) ? (window.asBinder()): (null)));
		_data.writeInt(seq);
		if ((attrs != null)) {
			_data.writeInt(1);
			attrs.writeToParcel(_data, 0);
		} else {
			_data.writeInt(0);
		}
		_data.writeInt(requestedWidth);
		_data.writeInt(requestedHeight);
		_data.writeInt(viewVisibility);
		_data.writeInt(flags);
		mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);
		_reply.readException();
		_result = _reply.readInt();
		if ((0 != _reply.readInt())) {
			outFrame.readFromParcel(_reply);
		}
		if ((0 != _reply.readInt())) {
			outOverscanInsets.readFromParcel(_reply);
		}
		if ((0 != _reply.readInt())) {
			outContentInsets.readFromParcel(_reply);
		}
		if ((0 != _reply.readInt())) {
			outVisibleInsets.readFromParcel(_reply);
		}
		if ((0 != _reply.readInt())) {
			outConfig.readFromParcel(_reply);
		}
		if ((0 != _reply.readInt())) {
			outSurface.readFromParcel(_reply);
		}
	} finally {
		_reply.recycle();
		_data.recycle();
	}
	return _result;
}

从该函数的实现能够看出,应用程序进程中创建的Surface对象并没有传递到WMS服务进程,仅仅是读取WMS服务进程返回来的Surface。那么WMS服务进程是怎样响应应用程序进程布局请求的呢?

frameworks\base\core\java\android\view\IWindowSession.java$ Stub

public boolean onTransact(int code, android.os.Parcel data,
		android.os.Parcel reply, int flags)throws android.os.RemoteException {
	switch (code) {
	case TRANSACTION_relayout: {
		data.enforceInterface(DESCRIPTOR);
		android.view.IWindow _arg0;
		_arg0 = android.view.IWindow.Stub.asInterface(data.readStrongBinder());
		int _arg1;
		_arg1 = data.readInt();
		android.view.WindowManager.LayoutParams _arg2;
		if ((0 != data.readInt())) {
			_arg2 = android.view.WindowManager.LayoutParams.CREATOR
					.createFromParcel(data);
		} else {
			_arg2 = null;
		}
		int _arg3;
		_arg3 = data.readInt();
		int _arg4;
		_arg4 = data.readInt();
		int _arg5;
		_arg5 = data.readInt();
		int _arg6;
		_arg6 = data.readInt();
		android.graphics.Rect _arg7;
		_arg7 = new android.graphics.Rect();
		android.graphics.Rect _arg8;
		_arg8 = new android.graphics.Rect();
		android.graphics.Rect _arg9;
		_arg9 = new android.graphics.Rect();
		android.graphics.Rect _arg10;
		_arg10 = new android.graphics.Rect();
		android.content.res.Configuration _arg11;
		_arg11 = new android.content.res.Configuration();
		android.view.Surface _arg12;
		_arg12 = new android.view.Surface();
		int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4,
				_arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12);
		reply.writeNoException();
		reply.writeInt(_result);
		if ((_arg7 != null)) {
			reply.writeInt(1);
			_arg7.writeToParcel(reply,
					android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
		} else {
			reply.writeInt(0);
		}
		if ((_arg8 != null)) {
			reply.writeInt(1);
			_arg8.writeToParcel(reply,
					android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
		} else {
			reply.writeInt(0);
		}
		if ((_arg9 != null)) {
			reply.writeInt(1);
			_arg9.writeToParcel(reply,
					android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
		} else {
			reply.writeInt(0);
		}
		if ((_arg10 != null)) {
			reply.writeInt(1);
			_arg10.writeToParcel(reply,
					android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
		} else {
			reply.writeInt(0);
		}
		if ((_arg11 != null)) {
			reply.writeInt(1);
			_arg11.writeToParcel(reply,
					android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
		} else {
			reply.writeInt(0);
		}
		if ((_arg12 != null)) {
			reply.writeInt(1);
			_arg12.writeToParcel(reply,
					android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
		} else {
			reply.writeInt(0);
		}
		return true;
	}
	}
}

该函数能够看出,WMS服务在响应应用程序进程请求加入窗体时,首先在当前进程空间创建一个Surface对象。然后调用Session的relayout()函数进一步完毕窗体加入过程,最后将WMS服务中创建的Surface返回给应用程序进程。

到眼下为止,在应用程序进程和WMS服务进程分别创建了一个Surface对象,可是他们调用的都是Surface的无參构造函数,在该构造函数中并未真正初始化native层的Surface,那native层的Surface是在那里创建的呢?

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

public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
		int requestedWidth, int requestedHeight, int viewFlags,
		int flags, Rect outFrame, Rect outContentInsets,
		Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
	int res = mService.relayoutWindow(this, window, seq, attrs,
			requestedWidth, requestedHeight, viewFlags, flags,
			outFrame, outContentInsets, outVisibleInsets,
			outConfig, outSurface);
	return res;
}

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

public int relayoutWindow(Session session, IWindow client, int seq,
		WindowManager.LayoutParams attrs, int requestedWidth,
		int requestedHeight, int viewVisibility, int flags,
		Rect outFrame, Rect outContentInsets,
		Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
	...
	synchronized(mWindowMap) {
		// TODO(cmautner): synchronize on mAnimator or win.mWinAnimator.
		WindowState win = windowForClientLocked(session, client, false);
		if (win == null) {
			return 0;
		}
		...
		if (viewVisibility == View.VISIBLE &&
				(win.mAppToken == null || !win.mAppToken.clientHidden)) {
			...
			try {
				if (!win.mHasSurface) {
					surfaceChanged = true;
				}
				//创建Surface
				Surface surface = winAnimator.createSurfaceLocked();
				if (surface != null) {
					outSurface.copyFrom(surface);
				} else {
					outSurface.release();
				}
			} catch (Exception e) {
				...
			}
			...
		}
		...
	}
	...
}

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

Surface createSurfaceLocked() {
	if (mSurface == null) {
		...
		try {
			...
			if (DEBUG_SURFACE_TRACE) {
				mSurface = new SurfaceTrace(
						mSession.mSurfaceSession, mSession.mPid,
						attrs.getTitle().toString(),
						0, w, h, format, flags);
			} else {
				mSurface = new Surface(
					mSession.mSurfaceSession, mSession.mPid,
					attrs.getTitle().toString(),
					0, w, h, format, flags);
			}
			mWin.mHasSurface = true;
		} catch (Surface.OutOfResourcesException e) {
			...
		}
		Surface.openTransaction();
		...
	}
	return mSurface;
}

Surface创建过程

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

public Surface(SurfaceSession s,int pid, String name, int display, int w, int h, int format, int flags)
	throws OutOfResourcesException {
	checkHeadless();
	if (DEBUG_RELEASE) {
		mCreationStack = new Exception();
	}
	mCanvas = new CompatibleCanvas();
	init(s,pid,name,display,w,h,format,flags);
	mName = name;
}

frameworks\base\core\jni\ android_view_Surface.cpp

static void Surface_init(
        JNIEnv* env, jobject clazz,
        jobject session,
        jint, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)
{
    if (session == NULL) {
        doThrowNPE(env);
        return;
    }
    SurfaceComposerClient* client =
            (SurfaceComposerClient*)env->GetIntField(session, sso.client);
    sp<SurfaceControl> surface;
    if (jname == NULL) {
        surface = client->createSurface(dpy, w, h, format, flags);
    } else {
        const jchar* str = env->GetStringCritical(jname, 0);
        const String8 name(str, env->GetStringLength(jname));
        env->ReleaseStringCritical(jname, str);
        surface = client->createSurface(name, dpy, w, h, format, flags);
    }
    if (surface == 0) {
        jniThrowException(env, OutOfResourcesException, NULL);
        return;
    }
    setSurfaceControl(env, clazz, surface);
}

到此才算真正创建了一个可用于画图的Surface,从上面的分析我们能够看出。在WMS服务进程端,事实上创建了两个Java层的Surface对象。第一个Surface使用了无參构造函数,只构造一个Surface对象而已,而第二个Surface却使用了有參构造函数。參数指定了图象宽高等信息,这个Java层Surface对象还会在native层请求SurfaceFlinger创建一个真正能用于绘制图象的native层Surface。最后通过浅拷贝的方式将第二个Surface拷贝到第一个Surface中。最后通过writeToParcel方式写回到应用程序进程。

到眼下为止。应用程序和WMS一共创建了3个Java层Surface对象。如上图所看到的,而真正能用于画图的Surface仅仅有3号,那么3号Surface与2号Surface之间是什么关系呢?outSurface.copyFrom(surface)

frameworks\base\core\jni\ android_view_Surface.cpp

static void Surface_copyFrom(JNIEnv* env, jobject clazz, jobject other)
{
    if (clazz == other)
        return;
    if (other == NULL) {
        doThrowNPE(env);
        return;
    }
	//得到当前Surface所引用的SurfaceControl对象
    const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
	//得到源Surface所引用的SurfaceControl对象
    const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
	//假设它们引用的不是同一个SurfaceControl对象
    if (!SurfaceControl::isSameSurface(surface, rhs)) {
        setSurfaceControl(env, clazz, rhs);
    }
}

2号Surface引用到了3号Surface的SurfaceControl对象后。通过writeToParcel()函数写会到应用程序进程。

frameworks\base\core\jni\ android_view_Surface.cpp

static void Surface_writeToParcel(
        JNIEnv* env, jobject clazz, jobject argParcel, jint flags)
{
    Parcel* parcel = (Parcel*)env->GetIntField(
            argParcel, no.native_parcel);
    if (parcel == NULL) {
        doThrowNPE(env);
        return;
    }
    const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
    if (control != NULL) {
        SurfaceControl::writeSurfaceToParcel(control, parcel);
    } else {
        sp<Surface> surface(Surface_getSurface(env, clazz));
        if (surface != NULL) {
            Surface::writeToParcel(surface, parcel);
        } else {
            SurfaceControl::writeSurfaceToParcel(NULL, parcel);
        }
    }
    if (flags & PARCELABLE_WRITE_RETURN_VALUE) {
        setSurfaceControl(env, clazz, NULL);
        setSurface(env, clazz, NULL);
    }
}

因为2号Surface引用的SurfaceControl对象不为空,因此这里就将SurfaceControl对象写会给应用程序进程

frameworks\native\libs\gui\ Surface.cpp

status_t SurfaceControl::writeSurfaceToParcel(
        const sp<SurfaceControl>& control, Parcel* parcel)
{
    sp<ISurface> sur;
    uint32_t identity = 0;
    if (SurfaceControl::isValid(control)) {
        sur = control->mSurface;
        identity = control->mIdentity;
    }
    parcel->writeStrongBinder(sur!=0 ?

sur->asBinder() : NULL);
    parcel->writeStrongBinder(NULL);  // NULL ISurfaceTexture in this case.
    parcel->writeInt32(identity);
    return NO_ERROR;
}

写入Parcel包裹的对象顺序例如以下:

应用程序进程中的1号Surface通过readFromParcel()函数读取从WMS服务进程写回的Binder对象。

frameworks\base\core\jni\ android_view_Surface.cpp

static void Surface_readFromParcel(
        JNIEnv* env, jobject clazz, jobject argParcel)
{
    Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);
    if (parcel == NULL) {
        doThrowNPE(env);
        return;
    }
    sp<Surface> sur(Surface::readFromParcel(*parcel));
    setSurface(env, clazz, sur);
}

frameworks\native\libs\gui\ Surface.cpp

sp<Surface> Surface::readFromParcel(const Parcel& data) {
    Mutex::Autolock _l(sCachedSurfacesLock);
    sp<IBinder> binder(data.readStrongBinder());
    sp<Surface> surface = sCachedSurfaces.valueFor(binder).promote();
    if (surface == 0) {
       surface = new Surface(data, binder);
       sCachedSurfaces.add(binder, surface);
    } else {
        // The Surface was found in the cache, but we still should clear any
        // remaining data from the parcel.
        data.readStrongBinder();  // ISurfaceTexture
        data.readInt32();         // identity
    }
    if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
        surface = 0;
    }
    cleanCachedSurfacesLocked();
    return surface;
}

应用程序进程中的1号Surface按相反顺序读取WMS服务端返回过来的Binder对象等数据。并构造一个native层的Surface对象。

Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
    : SurfaceTextureClient()
{
    mSurface = interface_cast<ISurface>(ref);
    sp<IBinder> st_binder(parcel.readStrongBinder());
    sp<ISurfaceTexture> st;
    if (st_binder != NULL) {
        st = interface_cast<ISurfaceTexture>(st_binder);
    } else if (mSurface != NULL) {
        st = mSurface->getSurfaceTexture();
    }
    mIdentity   = parcel.readInt32();
    init(st);
}

每一个Activity能够有一个或多个Surface,默认情况下一个Activity仅仅有一个Surface,当Activity中使用SurfaceView时,就存在多个Surface。Activity默认surface是在relayoutWindow过程中由WMS服务创建的。然后回传给应用程序进程。我们知道一个Surface事实上就是应用程序端的本地窗体,关于Surface的初始化过程这里就不在介绍。

performLayout

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

private void performLayout() {
	mLayoutRequested = false;
	mScrollMayChange = true;
	final View host = mView;
	if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
		Log.v(TAG, "Laying out " + host + " to (" +
				host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
	}
	Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
	try {
		host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
	} finally {
		Trace.traceEnd(Trace.TRACE_TAG_VIEW);
	}
}

performDraw

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

private void performDraw() {
	if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
		return;
	}
	final boolean fullRedrawNeeded = mFullRedrawNeeded;
	mFullRedrawNeeded = false;
	mIsDrawing = true;
	Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
	try {
		draw(fullRedrawNeeded);
	} finally {
		mIsDrawing = false;
		Trace.traceEnd(Trace.TRACE_TAG_VIEW);
	}
	...
}
private void draw(boolean fullRedrawNeeded) {
	Surface surface = mSurface;
	if (surface == null || !surface.isValid()) {
		return;
	}
	...
	if (!dirty.isEmpty() || mIsAnimating) {
		//使用硬件渲染
		if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
			// Draw with hardware renderer.
			mIsAnimating = false;
			mHardwareYOffset = yoff;
			mResizeAlpha = resizeAlpha;
			mCurrentDirty.set(dirty);
			mCurrentDirty.union(mPreviousDirty);
			mPreviousDirty.set(dirty);
			dirty.setEmpty();
			if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
					animating ? null : mCurrentDirty)) {
				mPreviousDirty.set(0, 0, mWidth, mHeight);
			}
		//使用软件渲染
		} else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
			return;
		}
	}
	...
}

窗体加入过程

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

public int add(IWindow window, int seq, WindowManager.LayoutParams attrs,
		int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
	return mService.addWindow(this, window, seq, attrs, viewVisibility, outContentInsets,
			outInputChannel);
}

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

public int addWindow(Session session, IWindow client, int seq,
		WindowManager.LayoutParams attrs, int viewVisibility,
		Rect outContentInsets, InputChannel outInputChannel) {
	//client为IWindow的代理对象。是Activity在WMS服务中的唯一标示
	int res = mPolicy.checkAddPermission(attrs);
	if (res != WindowManagerImpl.ADD_OKAY) {
		return res;
	}
	boolean reportNewConfig = false;
	WindowState attachedWindow = null;
	WindowState win = null;
	long origId;
	synchronized(mWindowMap) {
		if (mDisplay == null) {
			throw new IllegalStateException("Display has not been initialialized");
		}
		//推断窗体是否已经存在
		if (mWindowMap.containsKey(client.asBinder())) {
			Slog.w(TAG, "Window " + client + " is already added");
			return WindowManagerImpl.ADD_DUPLICATE_ADD;
		}
		//假设加入的是应用程序窗体
		if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
			//依据attrs.token从mWindowMap中取出应用程序窗体在WMS服务中的描写叙述符WindowState
			attachedWindow = windowForClientLocked(null, attrs.token, false);
			if (attachedWindow == null) {
				Slog.w(TAG, "Attempted to add window with token that is not a window: "
					  + attrs.token + ".  Aborting.");
				return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
			}
			if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
					&& attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
				Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
						+ attrs.token + ".  Aborting.");
				return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
			}
		}
		boolean addToken = false;
		//依据attrs.token从mWindowMap中取出应用程序窗体在WMS服务中的描写叙述符WindowState
		WindowToken token = mTokenMap.get(attrs.token);
		if (token == null) {
			...
			①token = new WindowToken(this, attrs.token, -1, false);
			addToken = true;
		}
		//应用程序窗体
		else if (attrs.type >= FIRST_APPLICATION_WINDOW
				&& attrs.type <= LAST_APPLICATION_WINDOW) {
			AppWindowToken atoken = token.appWindowToken;
			...
		}
		//输入法窗体
		else if (attrs.type == TYPE_INPUT_METHOD) {
			...
		}
		//墙纸窗体
		else if (attrs.type == TYPE_WALLPAPER) {
			...
		}
		//Dream窗体
		else if (attrs.type == TYPE_DREAM) {
			...
		}
		//为Activity窗体创建WindowState对象
		②win = new WindowState(this, session, client, token,
				attachedWindow, seq, attrs, viewVisibility);
		...
		if (outInputChannel != null && (attrs.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
			String name = win.makeInputChannelName();
			InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
			win.setInputChannel(inputChannels[0]);
			inputChannels[1].transferTo(outInputChannel);
			mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
		}
		...
		//以键值对<IWindow.Proxy/Token,WindowToken>形式保存到mTokenMap表中
		if (addToken) {
			③mTokenMap.put(attrs.token, token);
		}
		④win.attach();
		//以键值对<IWindow的代理对象,WindowState>形式保存到mWindowMap表中
		⑤mWindowMap.put(client.asBinder(), win);
		...
	}
	...
	return res;
}

我们知道当应用程序进程加入一个DecorView到窗体管理器时,会为当前加入的窗体创建ViewRootImpl对象。同一时候构造了一个W本地Binder对象,不管是窗体视图对象DecorView还是ViewRootImpl对象,都不过存在于应用程序进程中,在加入窗体过程中只将该窗体的W对象传递给WMS服务,经过Binder传输后。到达WMS服务端进程后变为IWindow.Proxy代理对象,因此该函数的參数client的类型为IWindow.Proxy。

參数attrs的类型为WindowManager.LayoutParams,在应用程序进程启动Activity时。handleResumeActivity()函数通过WindowManager.LayoutParams
l = r.window.getAttributes();来得到应用程序窗体布局參数,因为WindowManager.LayoutParams实现了Parcelable接口。因此WindowManager.LayoutParams对象能够跨进程传输,WMS服务的addWindow函数中的attrs參数就是应用程序进程发送过来的窗体布局參数。在LocalWindowManager的addView函数中为窗体布局參数设置了对应的token,假设是应用程序窗体。则布局參数的token设为W本地Binder对象。假设不是应用程序窗体,同一时候当前窗体没有父窗体。则设置token为当前窗体的IApplicationToken.Proxy代理对象,否则设置为父窗体的IApplicationToken.Proxy代理对象。因为应用程序和WMS分属于两个不同的进程空间。因此经过Binder传输后,布局參数的令牌attrs.token就转变为IWindow.Proxy或者Token。以上函数首先依据布局參数的token等信息构造一个WindowToken对象,然后在构造一个WindowState对象。并将加入的窗体信息记录到mTokenMap和mWindowMap哈希表中。

在WMS服务端创建了所需对象后。接着调用了WindowState的attach()来进一步完毕窗体加入。

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

void attach() {
	if (WindowManagerService.localLOGV) Slog.v(
		TAG, "Attaching " + this + " token=" + mToken
		+ ", list=" + mToken.windows);
	mSession.windowAddedLocked();
}

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

void windowAddedLocked() {
	if (mSurfaceSession == null) {
		mSurfaceSession = new SurfaceSession();
		if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
				WindowManagerService.TAG, "  NEW SURFACE SESSION " + mSurfaceSession);
		mService.mSessions.add(this);
	}
	mNumWindow++;//记录相应的某个应用程序加入的窗体数量
}

到此一个新的应用程序窗体就加入完毕了。

总结一下:

应用程序通过IWindowSession接口请求WMS服务加入一个应用程序窗体,WMS服务首先在自己服务进程为应用程序创建创建一个相应的WindowState描写叙述符,然后保存到成员变量mWindowMap中。假设还没有为应用程序进程创建连接SurfaceFlinger的会话,就接着创建该会话通道SurfaceSession。我们知道,Activity中的视图所使用的画布Surface是在WMS服务进程中创建的,可是该画布所使用的图形buffer确实在SurfaceFlinger进程中分配管理的,而图形的绘制确是在应用程序进程中完毕的,所以Activity的显示过程须要三个进程的配合才干完毕。应用程序进程仅仅与WMS服务进程交互。并不直接和SurfaceFlinger进程交互。而是由WMS服务进程同SurfaceFlinger进程配合。

前面我们介绍了应用程序进程是通过IWindowSession接口与WMS服务进程通信的,那WMS服务是怎样与SurfaceFlinger进程通信的呢,这就是windowAddedLocked函数要完毕的工作。

在windowAddedLocked函数中使用单例模式创建一个SurfaceSession对象,在构造该对象时。通过JNI在native层创建一个与SurfaceFlinger进程的连接。

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

public SurfaceSession() {
	init();
}

该init()函数是一个native函数。其JNI实现例如以下:

frameworks\base\core\jni\ android_view_Surface.cpp

static void SurfaceSession_init(JNIEnv* env, jobject clazz)
{
    sp<SurfaceComposerClient> client = new SurfaceComposerClient;
    client->incStrong(clazz);
    env->SetIntField(clazz, sso.client, (int)client.get());
}

该函数构造了一个SurfaceComposerClient对象。在第一次强引用该对象时,会请求SurfaceFlinger创建一个专门处理当前应用程序进程请求的Client会话。

每一个应用程序进程都持有一个与WMS服务会话通道IWindowSession,而服务端的Session有且仅仅有一个SurfaceSession对象。系统中创建的全部IWindowSession都被记录到WMS服务的mSessions成员变量中,这样WMS就能够知道自己正在处理那些应用程序的请求。到此我们来梳理一下在WMS服务端都创建了那些对象:

1)        WindowState对象。是应用程序窗体在WMS服务端的描写叙述符;

2)        Session对象,应用程序进程与WMS服务会话通道;

3)        SurfaceSession对象,应用程序进程与SurfaceFlinger的会话通道。

时间: 2024-09-30 00:04:24

Android应用程序窗体设计框架介绍的相关文章

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

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

Android 应用程序窗体显示状态操作(requestWindowFeature()的应用)(转载)

转自:http://www.cnblogs.com/salam/archive/2010/11/30/1892143.html 我们在开发程序是经常会需要软件全屏显示.自定义标题(使用按钮等控件)和其他的需求,今天这一讲就是如何控制Android应用程序的窗体显示. 首先介绍一个重要方法那就是requestWindowFeature(featrueId),它的功能是启用窗体的扩展特性.参数是Window类中定义的常量. 一.枚举常量 1.DEFAULT_FEATURES:系统默认状态,一般不需要

Android - 应用程序AndroidManifest Application节点介绍

一个Manifest只能包含一个application节点.他使用各种属性来指定应用程序的各种元数据(包括标题.图标和主题),在开发应用程序时,应该宝航一个设置有true的debuggable属性以启用调试,但是在发布时可以禁用该属性 application节点还可以作为一个包含了Activity.Service.Content Provider和Broadcast Receiver及诶单的容器,它包含的这些节点指定了应用程序组件. <application android:icon="@

android应用程序目录结构框架搭建

前言(废话) 在我们开始一个新android应用开发之前,我们需要新建一些目录结构.优秀的目录结构能让程序员一眼就能知道应用程序的构成结构,有助于帮助后来者理解代码.本人每每在拿到一个新的开发需求进行开发时,都有种不知如何下手的感觉,万事开头难,考虑到后来的扩展和不被后来人喷,经常在创建项目目录结构之初都会纠结很久(相信有不少新手会跟我有同样的心情吧O(∩_∩)O~).这次借鉴了网上和书籍的一些资料,自己整理了一份通用的模板,在这里做个笔记,也给新手做个参考. 声明:纯粹个人理解,还有很多考虑不

《基于 Bootstrap 的小程序UI设计框架》 一 CSS 通用样式

版式 标题 H1 到 H6 标题标签进行的优化.这里将不针对标签而是标题类 .H1 到 .H6.小程序仅识别 VIEW 标签. 重设上下边界为固定值,默认为一个行高距离,优化后统一为上 20 像素.下为 10 像素,h4 到 h6 距离顶部为 10 像素且不分标题级别,全部统一样式 固定所有标题行高为 1.1,避免行高因标题字体大小而变化,同时也避免不同级别标题行高不一致,影响版式风格统一 固定不同级别标题字体大小,依次为 36px 30px 24px 18px 14px 12px.这里将像素单

Android 应用程序窗体显示状态操作(requestWindowFeature()的应用)

http://www.cnblogs.com/salam/archive/2010/11/30/1892143.html

【电子书下载】《Android应用程序开发与典型案例》完整版!!

图书简介: <android应用程序开发与典型案例>共23章,内容包含两大部分.第一部分是android程序设计基础,在介绍android环境搭建以及android系统基本控件和组件后,详细介绍了android系统应用编程中典型的技术,比如,android中的图形图像.多媒体编程.gps定位与地图编程等:第二部分是android程序ui设计,从手机软件的交互设计谈起,介绍了android用户界面设计原则和方法.android用户界面设计哲学等,并给出了具体建议. <android应用程序

Android应用程序开发

Android应用程序开发 本章介绍了Android应用程序开发过程中涉及的控件,介绍了Activity转换和Internet消息传递.Menu设计修改.对话框实例和Android本地数据库SQLite应用. Android应用程序在开发期间有许多的文件需要协同管理和编辑,这就需要控件.控件分为视图控件(View).布局控件(ViewGroup).布局参数. Android应用程序设计中的常用控件:常用Widget控件,用Widget控件创建Android项目:按钮控件(Button)在Andr

Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8201936 在前文中,我们简要介绍了Android应用程序窗口的框架.Android应用程序窗口在运行的过程中,需要访问一些特定的资源或者类.这些特定的资源或者类构成了Android应用程序的运行上下文环境,Android应用程序窗口可以通过一个Context接口来访问它,这个Context接口也是我们在开发应用程序时经常碰到的.在本文中,我们