AMS和WMS


->startActivity() in ContextImpl.java
->getInstrumentation() in ActivityThread.java
->execStartActivity() in Instrumentation.java
->startActivity() in ActivityManagerNative.java
->通过Binder进入AMS
->startActivity() in ActivityManagerService.java
->startActivityAsUser() in ActivityManagerService.java
->startActivityMayWait() in ActivityStack.java
ActivityStack是专门实现对ActivityRecord的堆栈式管理而分离出来的一个模块。在Android2.2以前,对ActivityRecord的管理和调度都在ActivityManagerService实现。从android2.3以后,为了实现更好的解耦把对ActivityRecord的管理单独分离出来了,所有对ActivityRecord的调度操作都在ActivityStack里进行。其实Android里所谓的“Activity堆栈”,并不是真正的一个堆栈结构,而是一个ArrayList列表,在这个列表里记录了所有的ActivityRecord,ActivityStack所做的事情就是保证列表的第一个ActivityRecord(也就是“栈顶”)处于运行状态,并且排在列表后面的ActivityRecord的运行状态受到“栈顶”ActivityRecord的影响。

->startActivityLocked() in ActivityStack.java
这里面会创建一个ActivityRecord,分屏在这里修改。

->startActivityUncheckedLocked() in ActivityStack.java
TaskRecord记录了task的id、名称等属性。其中的tast的id就是AMS里面的自增加int变量mService.mCurTask。
而什么时候会新开一个Task,新开Task的名字等由ActivityStack里面的逻辑来判断,具体取决于AndroidManifest.xml中的配置和调用startActivity()时传递的flag。就在这个函数里面判断。
—如果源activity不存在,则直接开启一个新的tast。
—如果源activity是launch模式LAUNCH_SINGLE_INSTANCE,则开启一个新的tast。
—如果目标activity是launch模式LAUNCH_SINGLE_INSTANCE或LAUNCH_SINGLE_TASK,则开启一个新的tast。
新的tast直接new出来的,使用ActivityRecord.java->setTask设置给ActivityRecord,在++AMS里面的自增加int变量mService.mCurTask。

->startActivityLocked() in ActivityStack.java
前面说的ActivityStack.java是个管理ActivityRecord的模块,里面的列表mHistory就是谁有activity的堆栈。
在这里就会把前面同名函数>startActivityLocked里面创建的ActivityRecord加入到列表mHistory堆栈。
在ActivityStack里startActivityLocked()向mHistory添加新的ActivityRecord之后,
会紧跟向WMS添加这个Activity的token的封装对象AppWindowToken。
这时候这个Activity还是空中楼阁,后面AMS会先暂停当前Activity。这个Token后面会检查。
->startPausingLocked() in ActivityStack.java 下面通过ActivityRecord.app.thread调用Binder
->schedulePauseActivity() in ActivityThread.java
->handlePauseActivity() in ActivityThread.java
->performPauseActivity() in ActivityThread.java
->callActivityOnPause() in Instrumentation.java
->performPause() in Activity.java
回到前面handlePauseActivity() in ActivityThread.java最后通知AMS
->activityPaused() in AMS 下面再次调用
->resumeTopActivityLocked() in ActivityStack.java 注意这时候mResumeActivity为空
->resumeTopActivityLocked() in ActivityStack.java
在整个调度流程中,ActivityStack记录了列表中每个ActivityRecord的当前状态,包括这9个状态:
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}
每个ActivityRecord在任何时刻都处于这9个状态中的其中一个。

除此以外,ActivityStack还有许多功能函数用于辅助调度过程的:

除此以外,ActivityStack还有几个变量用于辅助调度过程的:
mResumedActivity指向当前系统中的“栈顶”Activity,当“栈顶”Activity将要被暂停时,mResumedActivity为空。
mPausingActivity指向该被暂停的Activity,直到Client端Activity响应onPause()之后回调AMS,mPausingActivity置空。

->resumeTopActivityLocked() in ActivityStack.java

在resumeTopActivityLocked()中,会判断ActivityRecord中的ProcessRecord app是否为空,这里有两种情况:
a) app不为空。
这种情况的前提是,Activity B并不是新打开的而是在一直在后台,并且其进程没有由于内存回收而杀掉。在这种情况下,会直接调用scheduleResumeActivity(),Client端会进行响应:onRestart()->onStart()->onResume()
b) app为空
app为空有三种情况,第一种是ActivityB之前一直在后台运行,由于内存不足被杀掉;第二种是Activity B是新打开的,并且不存在对应的进程;第三中情况是,Activity B 是新打开的,但是其进程仍在运行中。在第一、二种情况中,AMS会启动新进程,并完成Activity B和新进程的ProcessRecord的绑定。
在这三种情况中,最后都会调用scheduleLaunchActivity(),Client端会进响应:onCreate->onStart()->onResume()。

下面分情况看新的ActivityRecord的app变量是否为空,假如为空:
->startSpecificActivityLocked() in ActivityStack.java

例如从Launcher(A)打开新应用(B):
—调用resumeTopActivityLocked()。在resumeTopActivityLocked()中检查mResumedActivity是否为空,此时mResumedActivity指向A,所以肯定不为空。
—调用startPausingLocked()暂停A。此时将mResumedActivity置空,mPausingActivity指向A, 并且将A的状态置为PAUSING。接着调用Activity A的Client端的schedulePauseActivity()将其暂停。
—Client端的Activity 响应onPause()并且回调AMS的activityPaused()方法,将A的ActivityRecord的状态置为PAUSED,并把A添加到mStoppingActivities中。完成了A的暂停处理之后,会重新回到第2)步。在第二步中,此时mResumedActivity为空,接下来的流程会最终调用到Activity B 的Client端的scheduleLaunchActivity()。此时Activity B的状态变为RESUMED。
—ActivityB的Client端完成Activity的new和初始化并且响应onCreate()->onStart()->onResume(),然后回调AMS的activityIdle()方法告诉AMS已经运行完毕处于空闲状态。
—activityIdleLocked()主要是完成经过“堆栈”经过调整之后的“善后”工作。如根据finishing状态完成挂起的销毁操作,处理mStoppingActivities中的挂起stop操作。经过第4)步,A已经在mStoppingActivities中,所以接下来会调用A的Client端的scheduleStopActivity(booleanvisible),在Client端,根据接口参数visible判断,如果visible为false则响应onStop(),否则不响应。在ActivityStack中,visible的值是通过从上到下的计算得出的。如果“栈顶”Activity为fullscreen,则处于“栈顶”底下的其他activity的visible全为false。这个计算过程在第4)步中会执行一次或多次。在执行stop操作时,Activity A的状态从PAUSED变成STOPPING,再变成STOPPED。

这里会看新的ActivityRecord所在应用是否有进程了,如果没有:
->startProcessLocked() in ActivityManagerService.java
ProcessRecord记录了进程id、进程名字和各种用于调节优先级的状态。还包含了所有运行在该进程的Activity、Service、Receiver、Provider等组件。IApplicationThread thread记录了该进程中的主线程。当一个Acitivity第一次启动时,会首先调用Process.start(“android.app.ActivityThread”)来创建一个新进程并且生成一个ProcessRecord对象。当进程运行起来之后,该进程的主线程会调用Client端的ActivityThread.main()函数,在main()函数中完成Looper的prepare(),并且生成ActivityThread对象,接着在ActivityThread.attach()中调用IActivityManager.attachApplication()回到AMS,在AMS中完成ProcessRecord和IApplicationThread对象的绑定。接下来的流程就会把新Activity和ProcessRecord绑定。
->Process.start(“android.app.ActivityThread”, …) 这句code后面会mPidsSelfLock数组put进一个记录。
->main() in ActivityRecord.java
->attach() in ActivityRecord.java
->attachApplication() in AMS 先检查前面mPidsSelfLock有没有记录
然后绑定ProcessRecord和ActivityRecord的IBinder对象
->bindApplication() in ActivityRecord.java
->handleBindApplication() in ActivityRecord.java
->callApplicationOnCreate() in Instrumentation.java
->onCreate() in Application.java
回到前面AMS的attachApplictionLocked()
->realStartActivityLocked() in ActivityStack.java
->scheduleLaunchActivity() in ActivityThread.java
->handleLaunchActivity() in ActivityThread.java
->performLaunchActivity() in ActivityThread.java
这里会newActivity()生成Activity并且把Activity放入这个ActivityThread的mActivitys集合里面。
先调用attach() in Activity.java 关键一步
->callActivityOnCreate() in Instrumentation.java
->performCreate() in Activity.java
->onCreate() in Activity.java
———————————————————–
回到前面的attach() in Activity.java这一步
->makeNewWindow() in PolicyManager.java
->makeNewWindow() in Policy.java
这里面返回new出来的PhoneWindow,在PhoneWindow里有个DecorView作为顶层View,
DecorView下回包含一个mContentParent作为子View。
上面Activity的onCreate里调用的setContentView() in PhoneWindow.java就是
把用户布局内容addView到mContentParent里面去的。

->handleResumeActivity() in ActivityThread.java
这里面关键一步使用r.window.getDecorView()获取DecorView并且调用:
->windowManagerImpl的addView()
->addView() in WindowManagerGlobal.java
这里第一步检查所添加的窗口是否有存在mViews[]里面,不允许重复。
第二步判断窗口类型是否子窗口,FIRST_SUB_WINDOW,如果是就设置它的父亲
第三步创建ViewRootImpl
->第四步调用setView() in ViewRootImpl.java
说明ViewRootImpl类似一个Handler,它实现了ViewParent接口。我们可以:
第一:负责分发消息事件,如key,motion事件等等。
第二:负责和WMS的交互,分发WMS的交互命令。
第三:作为DecorView的父亲,对DecorView进行draw,measure,layout等等操作。
ViewRootImpl和WMS之间的双向对话,主要通过这两个IBinder:
IWindowSession 这是静态变量,代表一个进程只有一个,负责到WMS的单向请求
IWindow 这是非静态变量,一个进程可以有多个,负责WMS回调ViewRootImpl
->addToDisplay() in Session.java
->addWindow() in WMS
这里是真正向WMS申请创建,WMS先检查mTokenMap是否存在该token,前面有说明过,如果为空则会异常。
不为空则创建新的WindowState与ViewRootImpl对应,
并且把IWindow对象IBinder保存到WindowState里面作为WMS回调ViewRootImpl的接口。
到此为止,数据结构创建ok,client端的ViewRootImpl与WMS连接ok。
接下来WMS中一个WindowState要显示在屏幕上,就要申请一个surface,并且用copyFrom复制到ViewRootImpl里面。
就是说client端的ViewRootImpl和WMS都维护了一个指向同一块内存的mSurface对象。
->回到setView() in ViewRoorImpl.java
在调用addToDisplay前面有先调用创建surface的流程:
->requestLayout() in ViewRootImpl.java
->scheduleTraversals() in ViewRootImpl.java
->doTraversal() in ViewRootImpl.java
->performTraversals() in ViewRootImpl.java
->reLayoutWindow() in ViewRootImpl.java
->reLayout() in Session.java
->reLayoutWindow() in WMS
这里会调用createSurfaceLocked()创建surface,并且使用outSurface.copyFrom复制出去。
在WindowManager.java里面说了窗口类型有三种:
1.FIRST_APPLICATION_WINDOW ~ LAST_APPLICATION_WINDOW
是通常的顶级窗口,一般属于Activity的。
2.FIRST_SUB_WINDOW ~ LAST_SUB_WINDOW
是子窗口,子窗口必须attach到顶级窗口里面。
3.FIRST_SYSTEM_WINDOW ~ LAST_SYSTEM_WINDOW
是特殊的系统使用的窗口,比如状态栏,直接使用WMS的addView加进去。

 

----------------------------------------

问:普通view里面的surface如何从window的viewRoot传递过来?以及viewRoot的surface怎么创建的?
一个window有一个view hierarchy,位于顶点的是viewRoot,viewRoot不是一个view,因为里面是view和windowManager通讯协议的实现。
我们知道一个window必然在顶端有个frameLayout,这个frameLayout就是viewRoot里面的mView。
在viewRoot的performTraversals()里面会使用mView.dispatchAttachedToWindow(attachInfo, 0)传递View.AttachInfo给整个view树结构。
attachInfo(即是viewRoot的mAttachInfo)是在viewRoot的构造函数里面new出来的,并且viewRoot里面new了一个mSurface,然后在viewRoot的performTraversals()里面attachInfo.mSurface = mSurface;使得mSurface成为整个view树结构draw into的对象。

问:viewRoot如何获取surface的backBuffer和canvas传递给整个view树结构?
当用户请求绘制调用invalidate(),此函数会找到当前View或Viewgroup的ParentView,并调用父视图的 invalidateChild(this, r)。invalidateChild会循环调用父视图的invalidateChildInParent()因此层层向上层视图调用,直到调用到根视图 ViewRoot。ViewRoot的invalidateChildInParent调用invalidateChild,然后发送消息让 ViewRoot进行绘制。绘制代码在handleMessage()中的case DO_TRAVERSAL中调用了performTraversals()。
然后调用下一级视图的draw()函数。
draw()函数分析:
mUseGL标示window是否使用openGles来创建surface并作为draw into的对象。那么什么时候会需要openGles呢:在viewRoot的performTraversals()里面有如下代码:
if (mWindowAttributes.memoryType == WindowManager.LayoutParams.MEMORY_TYPE_GPU) {
if (params == null) {
params = mWindowAttributes;
}
mGlWanted = true;
}
这时就会使用openGles来创建surface并作为draw into的对象。

好了,下面回到draw()开头:
Surface surface = mSurface;
然后伪代码如下:
if (mUseGL) {
。。。。。。
} else {
。。。。。。
canvas = surface.lockCanvas(dirty);
。。。。。。

会依次调用以下几个函数:
background.draw(canvas)
onDraw(canvas)
dispatchDraw(canvas)
onDrawScrollBars(canvas)
。。。。。。
}

问:surface的创建流程?以及surface于surfaceFlinger服务怎么通讯?为什么surface.lockCanvas(dirty)就可以获取surface的backBuffer?
先从activity怎么启动开始讲:
->startActivity(Intent i) in Activity.java
->startActivityForResult(Intent i, -1) in Activity.java
。。。
http://g1a69.mail.126.com/js4/read/viewmail.jsp?sid=aBrKoKOSYkghmwstFiSSIZZwiJzObwjS&mid=44:1tbiLBPABkvUaK9mHAAAsb

问:系统服务加入ActivityManagerService以及为启动activity作准备的流程?开机后第一个launcher activity怎么启动?

->run() in calss ServerThread in SystemServer.java
->main() in ActivityManagerService.java
获得了(ActivityManagerService)mSelf
获得了(ActivityThread) mSystemThread
创建系统进程的ActivityThread和ApplicationThread(1)
->ActivityThread at = ActivityThread.systemMain();
in …… ActivityManagerService.java
->systemMain() in ActivityThread.java
->attach(true) in ActivityThread.java
创建系统进程所需的一些东西(2)
->startRunning() in ActivityManagerService.java
使得mStartRunning = true
->systemReady(null) in ActivityManagerService.java
一开始mSystemReady=false
直接return了。
-》回到setSystemProcess() in run() in calss ServerThread in SystemServer.java
根据前面的(1)(2)创建系统进程的processRecord.
系统服务加入ActivityManagerService
根据前面的(1)(2)是把放入framework-res.apk应用启动 shareUserId of 1000 , which is process of system_process.
-》回到 in run() in calss ServerThread in SystemServer.java
->ActivityManagerService.installSystemProviders();
USER PID PPID VSIZE RSS WCHAN PC NAME
system 60 33 179656 25224 ffffffff afd0db4c S system_server
install \frameworks\base\packages\settingsprovider
install \packages\apps\accountsandsyncsettings
->建立好所有系统服务后
-》systemReady(new(…)) in ActivityManagerService.java
->处理那些receiver可以接受ACTION_PRE_BOOT_COMPLETED
这里有2个app可以启动
\packages\providers\calendarprovider run in com.android.providers.calendar
\packages\providers\contactsprovider run in process android.process.acore
-》使得mSystemReady = true;
-》根据isAllowedWhileBooting检查清理当前进程。
-》处理是否运行工厂测试

->这是”com.android.phone”进程。
”“”“”“”“”“”不是根据前面的(1)(2),而是创建一个新的进程,不叫系统进程,的processRecord.“”“”“
在启动的时候, ActivityManagerService.systemReady将启动 android:persistent=”true” 的应用. 如下:
List apps = ActivityThread.getPackageManager().
getPersistentApplications(STOCK_PM_FLAGS);
if (apps != null) {
int N = apps.size();
int i;
for (i=0; i<N; i++) {
ApplicationInfo info
= (ApplicationInfo)apps.get(i);
if (info != null &&
!info.packageName.equals(“android”)) {//only framework-res.apk is “android”
addAppLocked(info);//here only PhoneApp
}
}
}
常驻应用在AndroidManifest.xml 中有android:persistent=”true”
-》resumeTopActivityLocked(null) in ActivityManagerService.java
-》startHomeActivityLocked() in ActivityManagerService.java
-> startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType,
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified)
in ActivityManagerService.java
在这里HistoryRecord r = new HistoryRecord(…)创建Launcher Activity的HistoryRecord数据结构
->doPendingActivityLaunchesLocked() in ActivityManagerService.java
->startActivityUncheckedLocked() in ActivityManagerService.java
在这里
mCurTask++;//创建新的任务堆栈编号
r.task = new TaskRecord(…)//创建新的任务堆栈记录数据结构,launcher activity是该任务堆栈的根activity。

->startActivityLocked(HistoryRecord r, boolean newTask, boolean doResume) in ActivityManagerService.java
在这里把launcher activity的HistoryRecord数据放入全局arryList里面mHistory。
->resumeTopActivityLocked(null) in ActivityManagerService.java
-》startSpecificActivityLocked(next, true, true) in ActivityManagerService.java
-》getProcessRecordLocked() in ActivityManagerService.java
这时mProcessNames里面是空的,返回null。
-》startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
“activity”, r.intent.getComponent(), false)
in ActivityManagerService.java
-》getProcessRecordLocked() in ActivityManagerService.java
这时mProcessNames里面依然是空的,返回null。
-》app = newProcessRecordLocked(null, info, processName);
in 。。。 ActivityManagerService.java
创建一个新的ProcessRecord数据结构
-》startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr)
in ActivityManagerService.java
-》int pid = Process.start(“android.app.ActivityThread”,
mSimpleProcessManagement ? app.processName : null, uid, uid,
gids, debugFlags, null);
in 。。。 ActivityManagerService.java
-》this.mPidsSelfLocked.put(pid, app);
in 。。。 ActivityManagerService.java
mPidsSelfLocked里面存放按pid索引的所有processRecord数据结构
-》main() in ActivityThread.java
这个函数在进程中创建一个ActivityThread实例,然后调用它的attach函数,接着就进入消息循环了,直到最后进程退出。
->新的进程通过ipc通讯调用AMS
-》attachApplication() in class ActivityManagerProxy ActivityManagerNative.java
->case ATTACH_APPLICATION_TRANSACTION in class ActivityManagerNative in ActivityManagerNative.java
->ApplicationThreadNative.asInterface(
data.readStrongBinder());
in ……. ActivityManagerNative.java
这里转换为ipc通道了。
-》attachApplication() in ActivityManagerService.java
-》attachApplicationLocked() in ActivityManagerService.java
-》app = mPidsSelfLocked.get(pid);
in 。。。 ActivityManagerService.java
-》realStartActivityLocked() in ActivityManagerService.java
->app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
r.info, r.icicle, results, newIntents, !andResume,
isNextTransitionForward());
in ……. ActivityManagerService.java
->提供ipc调用scheduleLaunchActivity() in class ApplicationThread Activity.java
-》queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
in ActivityThread.java
->mH.sendMessage(msg);
in ActivityThread.java
->case LAUNCH_ACTIVITY in handleMessage in ActivityThread.java

这里最后调用ActivityThread类的handleLaunchActivity函数进一步处理。

这里首先调用performLaunchActivity函数来加载这个Activity类,即 shy.luo.activity.MainActivity,然后调用它的onCreate函数,最后回到handleLaunchActivity函数时,再调用handleResumeActivity函数来使这个Activity进入Resumed状态,即会调用这个Activity的 onResume函数,这是遵循Activity的生命周期的。

http://g1a69.mail.126.com/js4/read/viewmail.jsp?sid=aBrKoKOSYkghmwstFiSSIZZwiJzObwjS&mid=44:1tbiLBPABkvUaK9mHAAAsb

共享UID

安装在设备中的每一个Android包文件(.apk)都会被分配到一个属于自己的统一的Linux用户ID,并且为它创建一个沙箱,以防止影响其 他应用程序(或者其他应用程序影响它)。用户ID 在应用程序安装到设备中时被分配,并且在这个设备中保持它的永久性。

通过SharedUserid,拥有同一个User id的多个APK可以配置成运行在同一个进程中.所以默认就是可以互相访问任意数据. 也可以配置成运行成不同的进程, 同时可以访问其他APK的数据目录下的数据库和文件.就像访问本程序的数据一样.
问:systemServer进程创建了那些服务?AMS服务在那个进程里面?c++空间的服务在那个进程?系统应用在那个进程里面?启动所有常驻应用,,in fact only PhoneApp?
String args[] = {
“–setuid=1000”,
“–setgid=1000”,
“–setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003”,
“–capabilities=130104352,130104352”,
“–runtime-init”,
“–nice-name=system_server”,
“com.android.server.SystemServer”,
};
USER PID PPID VSIZE RSS WCHAN PC NAME
system 60 33 179656 25224 ffffffff afd0db4c S system_server

systemServer进程创建了所有android层次服务,包括了AMS,见ActivityManagerService.setSystemProcess()。
AMS服务在systemServer进程里面。

process.java
/**
* Defines the UID/GID under which system code runs.
*/
public static final int SYSTEM_UID = 1000;

/**
* Defines the UID/GID under which the telephony code runs.
*/
public static final int PHONE_UID = 1001;

/**
* Defines the UID/GID for the user shell.
* @hide
*/
public static final int SHELL_UID = 2000;

/**
* Defines the UID/GID for the log group.
* @hide
*/
public static final int LOG_UID = 1007;

/**
* Defines the UID/GID for the WIFI supplicant process.
* @hide
*/
public static final int WIFI_UID = 1010;

/**
* Defines the start of a range of UIDs (and GIDs), going from this
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
* to applications.
*/
public static final int FIRST_APPLICATION_UID = 10000;
/**
* Last of application-specific UIDs starting at
* {@link #FIRST_APPLICATION_UID}.
*/
public static final int LAST_APPLICATION_UID = 99999;

/**
* Defines a secondary group id for access to the bluetooth hardware.
*/
public static final int BLUETOOTH_GID = 2000;
注意只有系统应用ramework-res.apk也在systemServer进程里面,见setSystemProcess() in ActivityManagerService.java,里面app.pid = MY_PID;MY_PID = Process.myPid();
只有系统应用framework-res.apk的包名是“android”,只有framework/base/core/res/AndroidManifest.xml里面是这样:
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”android” android:sharedUserId=”android.uid.system”
android:sharedUserLabel=”@string/android_system_label”>
为什么说统应用也在systemServer进程里面,因为android:sharedUserId=”android.uid.system”==1000
mSettings.addSharedUserLP(“android.uid.system”,
Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); in PackageManagerServer.java

c++空间的服务在那个进程即是Native Service是在系统Init阶 段通过Init.rc脚本建立的服务。但是在模拟器里面Native Service是在systemServer进程调用system_init() in system_init.cpp建立的。

问:Activity的finish()做了什么?

问:windowManager如何管理所以window?

问:surfaceView是什么?

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
view 里面的
/**
* This is called when the view is attached to a window. At this point it
* has a Surface and will start drawing. Note that this function is
* guaranteed to be called before {@link #onDraw}, however it may be called
* any time before the first onDraw — including before or after
* {@link #onMeasure}.
*
* @see #onDetachedFromWindow()
*/
protected void onAttachedToWindow() {
if ((mPrivateFlags & REQUEST_TRANSPARENT_REGIONS) != 0) {
mParent.requestTransparentRegion(this);
}
if ((mPrivateFlags & AWAKEN_SCROLL_BARS_ON_ATTACH) != 0) {
initialAwakenScrollBars();
mPrivateFlags &= ~AWAKEN_SCROLL_BARS_ON_ATTACH;
}
}

/**
* This is called when the view is detached from a window. At this point it
* no longer has a surface for drawing.
*
* @see #onAttachedToWindow()
*/
protected void onDetachedFromWindow() {
mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
removeUnsetPressCallback();
removeLongPressCallback();
destroyDrawingCache();
}

/**
* @param info the {@link android.view.View.AttachInfo} to associated with
* this view
*/
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
//System.out.println(“Attached! ” + this);
mAttachInfo = info;
mWindowAttachCount++;
if (mFloatingTreeObserver != null) {
info.mTreeObserver.merge(mFloatingTreeObserver);
mFloatingTreeObserver = null;
}
if ((mPrivateFlags&SCROLL_CONTAINER) != 0) {
mAttachInfo.mScrollContainers.add(this);
mPrivateFlags |= SCROLL_CONTAINER_ADDED;
}
performCollectViewAttributes(visibility);
onAttachedToWindow();
int vis = info.mWindowVisibility;
if (vis != GONE) {
onWindowVisibilityChanged(vis);
}
}

void dispatchDetachedFromWindow() {
//System.out.println(“Detached! ” + this);
AttachInfo info = mAttachInfo;
if (info != null) {
int vis = info.mWindowVisibility;
if (vis != GONE) {
onWindowVisibilityChanged(GONE);
}
}

onDetachedFromWindow();
if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) {
mAttachInfo.mScrollContainers.remove(this);
mPrivateFlags &= ~SCROLL_CONTAINER_ADDED;
}
mAttachInfo = null;
}