Android系统Activity窗口启动过程

更新时间:2024-04-10 03:28:02 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

在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(mServi ce.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,

AMS通过realStartActivityLocked函数来调度应用程序进程启动一个Activity,参数r为即将启动的Activity在AMS服务中的描述符,参数app为Activity运行所在的应用程序进程在AMS服务中的描述符。函数通过IApplicationThread代理对象

p

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 pendingResults, List 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: { getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);

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;

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 =

//启动Ac

r.intent.resolveActivity(mInitialApplication.getPackageManager()); ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } //通过类反射方式加载即将启动的Activity Activity activity = null; try { r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); if (r.state != null) { r.state.setClassLoader(cl); r.intent

java.lang

}

}

mInstrumentation); if (activity != null) { //为当前Activity创建上下文对象ContextImpl ContextImpl appContext = new ContextImpl(); //上下文初始化 ③appContext.init(r.packageInfo, r.token, this); appContext.setOuterContext(activity); 前启动的Activity和上下文ContextImpl、Application绑定 r.lastNonConfigurationInstances, config); ... ActivityClientRecord为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,

C④activi /r.activi

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 ref; if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) { ref = mPackages.get(packageName); } else { ref = mResourcePackages.get(packageName); } { ... return packageInfo; getPackageManager().getApplicationInfo(packageName, 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 ((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 ref; if (includeCode) { null; if (packageInfo == null || (packageInfo.mResources != null && !packageInfo.mResources.getAssets().isUpToDate())) { && (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0); WeakReference(packageInfo)); } else {

LoadedAp

} }PackageM

r

.

//保存Lo

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

PackageManager.getDataDirForUser(UserId.getUserId(myUid), 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(), 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, 的Application类名 String appClass = mApplicationInfo.className; //如果应用程序没用重写Application,则使用Android默认的Application类 if (forceDefaultAppClass || (appClass == null)) { new ContextImpl(); //初始化上下文 ②appContext.init(this, null, mActivityThread); //创建Application实例对象 ③app =

mActivityThread.mInstrumentation.newApplication( (instrumentation != null) { try { //调用

m

Instrume

appClass

cl, appC

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 != container.getCompatibilityInfo()); } mMainThread = mainThread; mContentResolver = new ApplicationContentResolver(this, mainThread); setActivityToken(activityToken);}

从ContextImpl的初始化函数中可以知道,ContextImpl记录了应用程序的包名信息、应用程序的资源信息、应用程序的主线程、ContentResolver及Activity对应的

IApplicationToken.Proxy,当然对应Application对象所拥有的ContextImpl上下文就没有对应的Token了。通过前面的分析我们可以知道各个对象之间的关系:

m

对象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, 员变量中 attachBaseContext(context); //每个Activity都拥有一

CharSequ

个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 = \IPolicy sPolicy;static { try { Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME); sPolicy = (IPolicy)policyClass.newInstance(); ex) { ... }}

} catch (ClassNotFoundException

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

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

return new

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

private static final String[] preload_classes = {

back\ te\

\android.internal.policy.impl.PhoneLayoutInflater\\\

\\\

\

try {

te$SavedState\static { for (String s : preload_classes) {

PhoneWindow的构造过程

C

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 Display.createCompatibleDisplay( mWindowManager.getDefaultDisplay().getDisplayId(), ci); }

mCompatibilityInfo = ci;}

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

? ((Comp

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

Display(int display, CompatibilityInfoHolder compatInfo) { synchronized (sStaticInit) { if (!sInitialized) { n

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; \java/lang/IllegalArgumentException\ return; 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

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所需要的窗口对象就创建完成了,在应用程序窗口的创建过程中一共创建了以下几个对象:

info.ydp} }

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(

我们知道在应用程序开发中,需要重写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的视图。

c

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

public void setContentView(int layoutResID) { //如果窗口顶级视图对象为空,则创建窗口视图对象 if (mContentParent == null) { installDecor(); } else {//否则只是移除该视图对象中的其他视图 Callback cb = getCallback(); if (cb != null && !isDestroyed()) {

mContentcb.onCon

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

m

}

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; && !a.mFinished && willBeVisible) { //获得为当前Activity创建的窗口PhoneWindow对象 r.window = r.activity.getWindow(); //获取为窗口创建的视图

try {

DecorView对象 View decor = r.window.getDecorView(); d

②WindowManager.LayoutParams l = r.window.getAttributes(); //将视图对象保存到Activity的成员变量mDecor中 a.mDecor = decor; { l.idleScreenAvailable = false; 器中 ③wm.addView(decor, l); r; Looper.myQueue().addIdleHandler(new Idler());

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

} } } l

我们知道Activity引用的其实是轻量级的窗口管理器LocalWindowManager frameworks/base/core/java/android/view/ Window.java

public final void addView(View view, ViewGroup.LayoutParams params) { && wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { if (wp.token == null) { View decor = peekDecorView(); if (decor != null) { { //根据窗口类型设置不同的标题 … if (mAppName != null) { mContainer.mAppToken; } if ((curTitle == null || curTitle.length() == 0) && mAppName != null) { wp.setTitle(mAppName); } } if (wp.packageName == null) { wp.packageName = mContext.getPackageName(); } if (mHardwareAccelerated) {

WindowMa

t

wp.flags

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, null; synchronized (this) { ... //从mViews中查找当前添加的View int index = findViewLocked(view, false); //如果已经存在,直接返回 if (index >= 0) { ... return; } int count = mViews != null ? mViews.length : 0; for (int i=0; i

Compatib

//尚未添

p

mViews =

old = mP

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( ViewConfiguration.get(context); mDensity =

context.getResources().getDisplayMetrics().densityDpi; mFallbackEventHandler =

PolicyManager.makeNewFallbackEventHandler(context); mProfileRendering = Boolean.parseBoolean( SystemProperties.get(PROPERTY_PROFILE_RENDERING, \ ④mChoreographer = Choreographer.getInstance(); PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mAttachInfo.mScreenOn = powerManager.isScreenOn(); loadSystemProperties();}

m

在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) { IWindowManager windowManager = Display.getWindowManager(); //得到IWindowSession代理对象 sWindowSession = windowManager.openSession(imm.getClient(), imm.getInputContext()); (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(\if (inputContext == null) throw new IllegalArgumentException(\Session session = new Session(this, client, inputContext); return session;}

t

在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机制

在Android4.1之后增加了Choreographer机制,用于同Vsync机制配合,实现统一调度界面绘图.

Choreographer构造过程

frameworks/base/core/java/android/view/Choreographer.java

public static Choreographer getInstance() { return sThreadInstance.get();}

private static final ThreadLocal sThreadInstance = IllegalStateException(\

为调用线程创建一个Choreographer实例,调用线程必须具备消息循环功能,因为ViewRootImpl对象的构造是在应用程序进程的UI主线程中执行的,因此创建的Choreographer对象将使用UI线程消息队列。

private Choreographer(Looper looper) { mLooper = looper; //创建消

息处理Handler mHandler = new FrameHandler(looper); //如果系统使用了Vsync机制,则注册一个FrameDisplayEventReceiver接收器 mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; mLastFrameTimeNanos = Long.MIN_VALUE; //屏幕刷新周期 mFrameIntervalNanos = (long)(1000000000 / new Display(Display.DEFAULT_DISPLAY,

new Thre}

null).getRefreshRate()); //创建回调数组 mCallbackQueues = new

CallbackQueue[CALLBACK_LAST + 1]; //初始化数组 for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new

CallbackQueue(); }}

变量USE_VSYNC用于表示系统是否是用了Vsync同步机制,该值是通过读取系统属性debug.choreographer.vsync来获取的。如果系统使用了Vsync同步机制,则创建一个FrameDisplayEventReceiver对象用于请求并接收Vsync事件,最后Choreographer创建了一个大小为3的CallbackQueue队列数组,用于保存不同类型的Callback。 添加回调过程

frameworks/base/core/java/android/view/Choreographer.java

public void postCallback(int callbackType, Runnable action, Object token) { postCallbackDelayed(callbackType, action, token, 0);} public void postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis) { if (action == null) { invalid\} postCallbackDelayedInternal(callbackType, action, token, delayMillis);}

private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; //将要执行的回调封装成CallbackRecord对象,保存到mCallbackQueues数组中 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); //函数执行时间到 if (dueTime <= now) { scheduleFrameLocked(now); } else {//通过异步消息方式实现函数延时执行 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); private final class FrameHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DO_SCHEDULE_CALLBACK: void doScheduleCallback(int callbackType) { synchronized (mLock) { { scheduleFrameLocked(now); private void scheduleFrameLocked(long now) { if (!mFrameScheduled) { (isRunningOnLooperThreadLocked()) { scheduleVsyncLocked(); } else {//如果当前线程不具备消息循环,则通过主线程请求VSync信号

throw ne

msg.arg1

d

if (!mFr} m

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);

final long nextFrameTime = Math.max( mHandler.obtainMessage(MSG_DO_FRAME); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, nextFrameTime); }}

}

在该函数中考虑了两种情况,一种是系统没有使用Vsync机制,在这种情况下,首先根据屏幕刷新频率计算下一次刷新时间,通过异步消息方式延时执行doFrame()函数实现屏幕刷新。如果系统使用了Vsync机制,并且当前线程具备消息循环,则直接请求Vsync信号,否则就通过主线程来请求Vsync信号。FrameDisplayEventReceiver对象用于请求并接收Vsync信号,当Vsync信号到来时,系统会自动调用其onVsync()函数,在该回调函数中执行doFrame()实现屏幕刷新。

当VSYNC信号到达时,Choreographer doFrame()函数被调用

void doFrame(long frameTimeNanos, int frame) { final long startNanos; synchronized (mLock) { if (!mFrameScheduled) { 花费的时间 final long jitterNanos = startNanos - frameTimeNanos; //如果线程处理该消息的时间超过了屏幕刷新周期 SKIPPED_FRAME_WARNING_LIMIT) { Log.i(TAG,

if (jitt

\ +

startNanos - lastFrameOffset; } //如果frameTimeNanos小于一个屏幕刷新周期,则重新请求VSync信号 if (frameTimeNanos < mLastFrameTimeNanos) { scheduleVsyncLocked(); return; } doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);}

mFrameSc

Choreographer类中分别定义了CallbackRecord、CallbackQueue内部类,CallbackQueue是一个按时间先后顺序保存CallbackRecord的单向循环链表。

在Choreographer中定义了三个CallbackQueue队列,用数组mCallbackQueues表示,用于分别保存CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL这三种类型的Callback,当调用Choreographer类的postCallback()函数时,就是往指定类型的CallbackQueue队列中通过addCallbackLocked()函数添加一个CallbackRecord项:首先构造一个CallbackRecord对象,然后按时间先后顺序插入到CallbackQueue链表中。从代码注释中,我们可以知道CALLBACK_INPUT是指输入回调,该回调优先级最高,首先得到执行,而CALLBACK_TRAVERSAL是指处理布局和绘图的回调,只有在所有异步消息都执行完后才得到执行,CALLBACK_ANIMATION是指动画回调,比CALLBACK_TRAVERSAL优先执行,从doFrame()函数中的doCallbacks调用就能印证这点。

doCallbacks(Choreographer.CALLBACK_INPUT,

frameTimeNanos);doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

当Vsync事件到来时,顺序执行CALLBACK_INPUT、CALLBACK_ANIMATION和CALLBACK_TRAVERSAL对应CallbackQueue队列中注册的回调。

void doCallbacks(int callbackType, long frameTimeNanos) { CallbackRecord callbacks; synchronized (mLock) { final long now = SystemClock.uptimeMillis(); //从指定类型的CallbackQueue队列中查找执行时间到的CallbackRecord

callbacks =

mCallbackQueues[callbackType].extractDueCallbacksLocked(now); if (callbacks == null) { return; } mCallbacksRunning = true; } try { //由于CallbackQueues是按时间先后顺序排序的,因此遍历执行所有时间到的CallbackRecord for (CallbackRecord c = callbacks; c != null; c = c.next) { c.run(frameTimeNanos); } } finally { synchronized (mLock) { mCallbacksRunning = false; do {

该函数就是按时间顺序先后执行到时的CallbackRecord

private static final class CallbackRecord { public CallbackRecord next; public long dueTime; public Object action; // Runnable or FrameCallback public Object token; public void run(long frameTimeNanos) { if (token == FRAME_CALLBACK_TOKEN) {

我们知道Choreographer对外提供了两个接口函数用于注册指定的Callback,postCallback()用于注册Runnable对象,而postFrameCallback()函数用于注册FrameCallback对象,无论注册的是Runnable对象还是FrameCallback对象,在

CallbackRecord对象中统一装箱为Object类型。在执行其回调函数时,就需要区别这两种对象类型,如果注册的是Runnable对象,则调用其run()函数,如果注册的是FrameCallback对象,则调用它的doFrame()函数。

f

(

Vsync请求过程

我们知道在Choreographer构造函数中,构造了一个FrameDisplayEventReceiver对象,用于请求并接收Vsync信号,Vsync信号请求过程如下:

private void scheduleVsyncLocked() { //申请Vsync信号 mDisplayEventReceiver.scheduleVsync();}

FrameDisplayEventReceiver继承于DisplayEventReceiver类,Vsync请求在DisplayEventReceiver中实现。

frameworks/base/core/java/android/view/ DisplayEventReceiver.java

public void scheduleVsync() { if (mReceiverPtr == 0) { Log.w(TAG, \display event \ + \disposed.\} else { //通过Jni方式调用native层的NativeDisplayEventReceiver对象来请求VSync nativeScheduleVsync(mReceiverPtr); }}

frameworks/base/core/jni/ android_view_DisplayEventReceiver.cpp

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jint receiverPtr) { //得到NativeDisplayEventReceiver对象指针 sp receiver = reinterpret_cast(receiverPtr); //通过NativeDisplayEventReceiver请求VSync status_t status = receiver->scheduleVsync(); if (status) { String8 message; message.appendFormat(\next vertical

sync pulse.status=%d\

jniThrowRuntimeException(env, message.string()); }} status_t NativeDisplayEventReceiver::scheduleVsync() { if (!mWaitingForVsync) { ALOGV(\%p ~ Scheduling vsync.\this); // Drain all pending events. nsecs_t vsyncTimestamp; uint32_t vsyncCount; readLastVsyncMessage(&vsyncTimestamp, &vsyncCount); status_t status = mReceiver.requestNextVsync(); if (status) { ALOGW(\next vsync, status=%d\ return status; } mWaitingForVsync = true; } return OK;}

VSync请求过程又转交给了DisplayEventReceiver frameworks/native/libs/gui/ DisplayEventReceiver.cpp

status_t DisplayEventReceiver::requestNextVsync() {if (mEventConnection != NULL)

{mEventConnection->requestNextVsync();return NO_ERROR;}return NO_INIT;}

这里又通过IDisplayEventConnection接口来请求Vsync信号,IDisplayEventConnection实现了Binder通信框架,可以跨进程调用,因为Vsync信号请求进程和Vsync产生进程有可能不在同一个进程空间,因此这里就借助IDisplayEventConnection接口来实现。下面通过图来梳理Vsync请求的调用流程:

视图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) { = new TakenSurfaceHolder(); mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); null; mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale; if (panelParentView != null) { mAttachInfo.mPanelParentWindowToken WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { true; collectViewAttributes(); mWindowAttributes, getHostVisibility(), mAttachInfo.mContentInsets, RootViewSurfaceTaker) { mInputQueueCallback = ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); InputQueue(mInputChannel); mInputQueueCallback.onInputQueueCreated(mInputQueue);

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

mSurface

}

= /

}

}

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

//向Chor

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

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

final TraversalRunnable mTraversalRunnable = new

TraversalRunnable();final class TraversalRunnable implements Runnable {@Overridepublic void run() {doTraversal();}}

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

void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);

{ performTraversals(); } finally {

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

viewVisibility, insetsPending); ... }

catch (RemoteException e) { } ... if (!mStopped) { boolean

if (mPro T

|| mNewS

viewVisi

focusChangedDueToTouchMode = ensureTouchModeLocally( ... }

(

host.getMeasuredHeight() || contentInsetsChanged) { childHeightMeasureSpec); ...

didLayout ||

attachInfo.mRecomputeGlobalAttributes; if (didLayout) { performLayout(); ... } ... /****************查找窗口焦点******************/ boolean skipDraw = false; if (mFirst) { // handle first focus request if (DEBUG_INPUT_RESIZE) Log.v(TAG, \mView.hasFocus()=\ + mView.hasFocus()); mView.findFocus(); if (DEBUG_INPUT_RESIZE) Log.v(TAG, \ view=\ + mRealFocusedView); doing window animations, we want to hold of on any future ******************/ mFirst = false; mWillDrawSoon = false; mNewSurfaceNeeded = false; mViewVisibility = viewVisibility; ... boolean cancelDraw =

attachInfo.mTreeObserver.dispatchOnPreDraw() || viewVisibility != View.VISIBLE; if (!cancelDraw && !newSurface) { if (!skipDraw || mReportNextDraw) { { mPendingTransitions.get(i).startChangingAnimations(); again scheduleTraversals(); } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {

performMeasure

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

private void performMeasure(int childWidthMeasureSpec, int

childHeightMeasureSpec) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, \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 {

if (mVie

+ }// draws

i

}

f

... int relayoutResult = sWindowSession.relayout(

mWindow,

insetsPending ? WindowManagerImpl.RELAYOUT_INSETS_PENDING : 0,

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

m

private final Surface mSurface = new Surface();

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

public Surface() { checkHeadless(); if (DEBUG_RELEASE) { mCreatio

该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); { _data.writeInt(0); } _data.writeInt(requestedWidth); _data.writeInt(requestedHeight); _data.writeInt(viewVisibility); _data.writeInt(flags); mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);

a

_reply.readException(); _result =

_reply.readInt(); if ((0 != _reply.readInt())) { { outContentInsets.readFromParcel(_reply); outFrame

}

{ 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()); android.view.WindowManager.LayoutParams.CREATOR

_arg5; _arg5 = data.readInt(); int _arg6; android.graphics.Rect(); android.graphics.Rect _arg9;

android.content.res.Configuration(); android.view.Surface _arg12; _arg12 = new android.view.Surface(); int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, { reply.writeInt(1); _arg7.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } if ((_arg8 != null)) { reply.writeInt(1);

{ 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,

int _arg

._arg6 = _arg9 =

_

_

else {

else {

android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); reply.writeInt(0); } if ((_arg11 != null)) { reply.writeInt(1);

_arg11.writeToParcel(reply,

android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); reply.writeInt(0); } if ((_arg12 != null)) { reply.writeInt(1);

_arg12.writeToParcel(reply,

android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);

reply.writeInt(0);

} }}

}

}

}

}

else {

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, flags, outFrame, outContentInsets, outVisibleInsets,

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

Rect out

o

public int relayoutWindow(Session session, IWindow client, int seq,

Configuration outConfig, Surface outSurface) { ... synchronized(mWindowMap) { // TODO(cmautner):

WindowMa

synchronize on mAnimator or win.mWinAnimator. WindowState win

= windowForClientLocked(session, client, false); if (win == null) { return 0; } ... if (viewVisibility == View.VISIBLE && (

true; } //创建Surface Surface surface = winAnimator.createSurfaceLocked(); if (surface != null) { outSurface.copyFrom(surface); } else {

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

Surface createSurfaceLocked() { if (mSurface == null) {

mSession.mPid, attrs.getTitle().toString(),

mSession.mPid, attrs.getTitle().toString(), 0, w, h, format, flags);

}

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, { doThrowNPE(env); return; } SurfaceComposerClient* client = (SurfaceComposerClient*)env->GetIntField(session, sso.client); sp surface; if (jname == NULL) { surface = client->createSurface(dpy, w, h, format, flags); } else { const jchar* str = env->GetStringCritical(jname, 0); 0) { jniThrowException(env, OutOfResourcesException, NULL); return; } setSurfaceControl(env, clazz, surface);}

到此才算真正创建了一个可用于绘图的Surface,从上面的分析我们可以看出,在WMS服务进程端,其实创建了两个Java层的Surface对象,第一个Surface使用了无参构造函数,

...

0, w, h,

mWin.mHa

jobject

const St

仅仅构造一个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) { SurfaceControl对象 const sp& 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

doThrowN

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& control(getSurfaceControl(env, clazz)); if (control != NULL) { { Surface::writeToParcel(surface, parcel); NULL); setSurface(env, clazz, NULL); }}

由于2号Surface引用的SurfaceControl对象不为空,因此这里就将SurfaceControl对象写会给应用程序进程 frameworks/native/libs/gui/ Surface.cpp

SurfaceC

} else {

status_t SurfaceControl::writeSurfaceToParcel( const

sp& control, Parcel* parcel){ sp 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 sur(Surface::readFromParcel(*parcel)); setSurface(env, clazz, sur);}

frameworks/native/libs/gui/ Surface.cpp

sp Surface::readFromParcel(const Parcel& data) { Mutex::Autolock _l(sCachedSurfacesLock); sp binder(data.readStrongBinder()); sp 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 surface;}

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

data.rea

Surface::Surface(const Parcel& parcel, const sp& ref) :

SurfaceTextureClient(){ mSurface = interface_cast(ref); sp

st_binder(parcel.readStrongBinder()); sp st; if (st_binder != NULL) { st =

interface_cast(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, \ 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, \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) {

host.get

//使用硬件渲染 if

(attachInfo.mHardwareRenderer != null &&

attachInfo.mHardwareRenderer.isEnabled()) { // Draw with hardware renderer. mIsAnimating = false; resizeAlpha; mCurrentDirty.set(dirty); this, animating ? null : mCurrentDirty)) { mPreviousDirty.set(0, 0, mWidth, mHeight); } //使用软件渲染 } else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) { return; } } ...}

m

mCurrent

窗口添加过程

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, = 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) { { Slog.w(TAG, \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, \window: \ + attrs.token + \ return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; } that is a sub-window: \ + attrs.token + \ return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; } mTokenMap.get(attrs.token); if (token == null) { FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW) { AppWindowToken atoken = token.appWindowToken; ... } //输入法窗口 else if (attrs.type == TYPE_INPUT_METHOD) { ... } //墙纸窗口 = new WindowState(this, session, client, token, { String name = win.makeInputChannelName(); InputChannel.openInputChannelPair(name);

WindowMa

i

}

...

else if attached I

win.setInputChannel(inputChannels[0]);

inputChannels[1].transferTo(outInputChannel);

mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); } ... //以键值对形式保存到mTokenMap表中 if (addToken) { ③mTokenMap.put(attrs.token, token); } ④win.attach(); //以键值对形式保存到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, \+ \list=\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(

到此一个新的应用程序窗口就添加完成了。总结一下:

应用程序通过IWindowSession接口请求WMS服务添加一个应用程序窗口,WMS服务首先在自己服务进程为应用程序创建创建一个对应的WindowState描述符,然后保存到成员变量mWindowMap中。如果还没有为应用程序进程创建连接SurfaceFlinger的会话,就接着创建该会话通道SurfaceSession,我们知道,Activity中的视图所使用的画布Surface是在WMS服务进程中创建的,但是该画布所使用的图形buffer确实在SurfaceFlinger进程中分配管理的,而图形的绘制确是在应用程序进程中完成的,所以Activity的显示过程需要三个进程的配合才能完成。应用程序进程只与WMS服务进程交互,并不直接和SurfaceFlinger进程交互,而是由WMS服务进程同SurfaceFlinger进程配合。前面我们介绍了应用程序进程是通过IWindowSession接口与WMS服务进程通信的,那WMS服务是如何与SurfaceFlinger进程通信的呢,这就是windowAddedLocked函数要完成的工作。

WindowMa

在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 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的会话通道; Android 调度系统 应用程序 相关文章

? ? ?

Android JNI 之 JNIEnv 解析 android实现左右滑动界面

Android 使用 DownloadManager 管理系统下载任务的方

? ? ? ? ?

Android笔记之 文件保存、压缩与清空删除 Android 应用程序签名

Android Touch事件传递机制详解 下 Android -- Drawable与Bitmap

Android开发之IPC进程间通信-AIDL介绍及实例解析

本文来源:https://www.bwwdw.com/article/593r.html

Top