App在后台久置后,再次从桌面或最近的任务列表唤醒时常常会发生崩溃,这每每是App在后台被系统杀死,再次恢复的时候遇到了问题,而在使用FragmentActivity+Fragment的时候,常常会遇到:好比Fragment没有提供默认构造方法,就会重建的时候由于反射建立Fragment失败而崩溃,再好比,在onCreate里面new 一个FragmentDialog,而且show,在被后台杀死,再次唤醒的时候,就会show两个对话框,这是为何?其实这就涉及了后台杀死及恢复的机制。java
当App被后台异常杀死后,再次点击icon,或者从最近任务列表进入的时候,系统会帮助恢复当时的场景,从新建立Activity,对于FragmentActivity,因为其中有Framgent,逻辑会相对再复杂一些,系统会首先重建被销毁的Fragment。看FragmentActivity的onCreat代码:node
咱们建立一个Activity,而且在onCreate函数中新建并show一个DialogFragment,以后经过某种方式将APP异常杀死(RogueKiller模拟后台杀死工具),再次从最近的任务唤起App的时候,会发现显示了两个DialogFragment,代码以下:android
public class DialogFragmentActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DialogFragment dialogFragment = new FragmentDlg();
dialogFragment.show(getSupportFragmentManager(), "");
}
复制代码
虽然被杀死了,可是onCreate函数在执行的时候仍是只执行了一次啊,为何会出现两个DialogFragment,这里其实就有一个DialogFragment是经过Android自身的恢复重建机制重建出来,在异常杀死的状况下onCreate(Bundle savedInstanceState)函数的savedInstanceState参数也不是null,而是包含了被杀死时所保存的场景信息。再来看个崩溃的例子,新建一个CrashFragment,而且丢弃默认无参构造方法:后端
public class CrashFragment extends Fragment {
public CrashFragment(String tag) {
super();
}
}
复制代码
以后再Activity中Add或replace添加这个CrashFragment,在CrashFragment显示后,经过RogueKiller模拟后台杀死工具模拟后台杀死,再次从最近任务列表里唤起App的时候,就会遇到崩溃,缓存
Caused by: android.support.v4.app.Fragment$InstantiationException:
Unable to instantiate fragment xxx.CrashFragment:
make sure class name exists, is public, and has an empty constructor that is public
at android.support.v4.app.Fragment.instantiate(Fragment.java:431)
at android.support.v4.app.FragmentState.instantiate(Fragment.java:102)
at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1952)
at android.support.v4.app.FragmentController.restoreAllState(FragmentController.java:144)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:307)
at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:81)
复制代码
上面的这两个问题主要涉及后台杀死后FragmentActivity自身的恢复机制,其实super.onCreate(savedInstanceState)在恢复时作了不少咱们没有看到的事情,先看一下崩溃:bash
看一下support-V4中FragmentActivity中onCreate代码以下:服务器
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
...
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
}
mFragments.dispatchCreate();
}
复制代码
能够看到若是savedInstanceState != null,就会执行mFragments.restoreAllState逻辑,其实这里就牵扯到恢复时重建逻辑,再被后台异常杀死前,或者说在Activity的onStop执行前,Activity的现场以及Fragment的现场都是已经被保存过的,实际上是被保存早ActivityManagerService中,保存的格式FragmentState,重建的时候,会采用反射机制从新创Fragmentcookie
void restoreAllState(Parcelable state, List<Fragment> nonConfig) {
...
for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
Fragment f = fs.instantiate(mHost, mParent);
mActive.add(f);
...
复制代码
其实就是调用FragmentState的instantiate,进而调用Fragment的instantiate,最后经过反射,构建Fragment,也就是,被加到FragmentActivity的Fragment在恢复的时候,会被自动建立,而且采用Fragment的默认无参构造方法,若是没哟这个方法,就会抛出InstantiationException异常,这也是为何第二个例子中会出现崩溃的缘由。网络
*/
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
try {
Class<?> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache, see if it's real, and try to add it clazz = context.getClassLoader().loadClass(fname); sClassMap.put(fname, clazz); } Fragment f = (Fragment)clazz.newInstance(); if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); f.mArguments = args; } return f; } catch (ClassNotFoundException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (java.lang.InstantiationException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (IllegalAccessException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } } q 能够看到场景二提示的errormsg跟抛出的异常是能够对应上的,其实Fragment源码里面也说得很清楚: /** * Default constructor. <strong>Every</strong> fragment must have an * empty constructor, so it can be instantiated when restoring its * activity's state. It is strongly recommended that subclasses do not
* have other constructors with parameters, since these constructors
* will not be called when the fragment is re-instantiated; instead,
* arguments can be supplied by the caller with {@link #setArguments}
* and later retrieved by the Fragment with {@link #getArguments}.
*
* <p>Applications should generally not implement a constructor. The
* first place application code an run where the fragment is ready to
* be used is in {@link #onAttach(Activity)}, the point where the fragment
* is actually associated with its activity. Some applications may also
* want to implement {@link #onInflate} to retrieve attributes from a
* layout resource, though should take care here because this happens for
* the fragment is attached to its activity.
*/
public Fragment() {
}
复制代码
大意就是,Fragment必须有一个空构造方法,这样才能保证重建流程,而且,Fragment的子类也不推荐有带参数的构造方法,最好采用setArguments来保存参数。下面再来看下为何会出现两个DialogFragment。架构
Fragment在被建立以后,若是不经过add或者replace添加到Activity的布局中是不会显示的,在保存现场的时候,也是保存了add的这个状态的,来看一下Fragment的add逻辑:此时被后台杀死,或旋转屏幕,被恢复的DialogFragmentActivity时会出现两个FragmentDialog,一个被系统恢复的,一个新建的。
一般咱们FragmentActivity使用Fragment的方法以下:假设是在oncreate函数中:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fragment fr = Fragment.instance("")
getSupportFragmentManager().beginTransaction()
.add(R.id.container,fr).commit();
复制代码
其中getSupportFragmentManager返回的是FragmentManager的子类FragmentManagerImpl,FragmentManagerImpl是FragmentActivity的一个内部类,其Fragment的管理逻辑都是由FragmentManagerImpl来处理的,本文是基于4.3,后面的高版本引入了FragmentController其实也只是多了一层封装,原理差异不是太大,有兴趣能够本身分析:
public class FragmentActivity extends Activity{
...
final FragmentManagerImpl mFragments = new FragmentManagerImpl();
...
final FragmentContainer mContainer = new FragmentContainer() {
@Override
@Nullable
public View findViewById(int id) {
return FragmentActivity.this.findViewById(id);
}
@Override
public boolean hasView() {
Window window = FragmentActivity.this.getWindow();
return (window != null && window.peekDecorView() != null);
}
};
复制代码
FragmentManagerImpl的beginTransaction()函数返回的是一个BackStackRecord()
@Override
public FragmentTransaction beginTransaction() {
return new (this);
}
复制代码
从名字就能够看出,beginTransaction是为FragmentActivity生成一条Transaction(事务),能够执行,也能够反向,做为退栈的一个依据,FragmentTransaction的add函数实现以下,
public FragmentTransaction add(Fragment fragment, String tag) {
doAddOp(0, fragment, tag, OP_ADD);//异步操做的,跟Hander相似
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
...
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
复制代码
以后commit这个Transaction, 将Transaction插入到Transaction队列中去,最终会回调FragmentManager的addFragment方法,将Fragment添加FragmentManagerImpl到维护Fragment列表中去,而且根据当前的Activity状态,将Fragment调整到合适的状态,代码以下:
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
makeActive(fragment);
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
if (moveToStateNow) {
moveToState(fragment);
}
}
}
复制代码
为何说FragmentManager是FragmentActivity管理Fragment的核心呢,请看下面:
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
...
ArrayList<Runnable> mPendingActions;
Runnable[] mTmpActions;
boolean mExecutingActions;
ArrayList<Fragment> mActive;
ArrayList<Fragment> mAdded;
ArrayList<Integer> mAvailIndices;
ArrayList<BackStackRecord> mBackStack;
复制代码
能够看出FragmentManagerImpl帮FragmentActivity维护着全部管理Fragment的列表,FragmentManagerImpl的State是和Activity的State一致的,这是管理Fragment的关键。其实Fragment自身是没有什么生命周期的,它只是一个View的封装,彻底依靠FragmentManagerImpl来进行同步模拟生命周期,好比在onCreate函数中建立Fragment,add后,在执行的到Activity自身的onCreateView以前,Fragment的onCreateView是不会执行的,也就是Fragment是被动式的跟FragmentActivity保持一致。既然Fragment只是个View的封装,那么它是如何转换成View,并添加到Container中去的呢?关键是moveToState函数,这个函数强制将新add的Fragment的生命周期与Activity同步:
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
...
if (f.mState < newState) { //低于当前Activity的状态
switch (f.mState) {
case Fragment.INITIALIZING:
...
f.mActivity = mActivity;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mActivity.mFragments;
f.mCalled = false;
f.onAttach(mActivity);
...
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
}
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
f.onViewCreated(f.mView, f.mSavedFragmentState);
f.performActivityCreated(f.mSavedFragmentState);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
f.mResumed = true;
f.performResume();
复制代码
能够看出,add Fragment以后,须要让Fragment跟当前Activity的State保持一致。如今回归正题,对于后台杀死状态下,为何会show两个DialogFragment呢,咱们须要接着看就要Fragment的异常处理的流程,在Fragment没有无参构造方法会引起崩溃里面,分析只是走到了Fragment的构建,如今接着往下走。提供无参构造函数后,Fragment能够正确的新建出来,以后呢?以后就是一些恢复逻辑,接着看restoreAllState:
void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
if (state == null) return;
FragmentManagerState fms = (FragmentManagerState)state;
mActive = new ArrayList<Fragment>(fms.mActive.length);
for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
Fragment f = fs.instantiate(mActivity, mParent);
mActive.add(f);
fs.mInstance = null;
// Build the list of currently added fragments.
if (fms.mAdded != null) {
mAdded = new ArrayList<Fragment>(fms.mAdded.length);
for (int i=0; i<fms.mAdded.length; i++) {
Fragment f = mActive.get(fms.mAdded[i]);
if (f == null) {
throwException(new IllegalStateException(
"No instantiated fragment for index #" + fms.mAdded[i]));
}
f.mAdded = true;
if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
if (mAdded.contains(f)) {
throw new IllegalStateException("Already added!");
}
mAdded.add(f);
}
// Build the back stack.
if (fms.mBackStack != null) {
mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
for (int i=0; i<fms.mBackStack.length; i++) {
BackStackRecord bse = fms.mBackStack[i].instantiate(this);
mBackStack.add(bse);
if (bse.mIndex >= 0) {
setBackStackIndex(bse.mIndex, bse);
}
复制代码
其实到如今如今Fragment相关的信息已经恢复成功了,以后随着FragmentActivity周期显示或者更新了,这些都是被杀死后,在FragmentActiivyt的onCreate函数处理的,也就是默认已经将以前的Fragment添加到mAdded列表中去了,可是,在场景一,咱们有手动新建了一个Fragment,并添加进去,因此,mAdded函数中就有连个两个Fragment。这样,在FragmentActivity调用onStart函数以后,会新建mAdded列表中Fragment的视图,将其添加到相应的container中去,并在Activity调用onReusume的时候,显示出来作的,这个时候,就会显示两份,其实若是,在这个时候,你再杀死一次,恢复,就会显示三分,在杀死,重启,就是四份。。。。
@Override
protected void onStart() {
super.onStart();
mStopped = false;
mReallyStopped = false;
mHandler.removeMessages(MSG_REALLY_STOPPED);
if (!mCreated) {
mCreated = true;
mFragments.dispatchActivityCreated();
}
mFragments.noteStateNotSaved();
mFragments.execPendingActions();
mFragments.doLoaderStart();
// NOTE: HC onStart goes here.
mFragments.dispatchStart();
mFragments.reportLoaderStart();
}
复制代码
以上就是针对两个场景,对FramgentActivity的一些分析,主要是回复时候,对于Framgent的一些处理。
在在点击home键,或者跳转其余界面的时候,都会回调用onSaveInstanceState,可是再次唤醒却不必定调用OnRestoreInstance,这是为何呢?onSaveInstanceState与OnRestoreInstance难道不是配对使用的?在Android中,onSaveInstanceState是为了预防Activity被后台杀死的状况作的预处理,若是Activity没有被后台杀死,那么天然也就不须要进行现场的恢复,也就不会调用OnRestoreInstance,而大多数状况下,Activity不会那么快被杀死。
onSaveInstanceState函数是Android针对可能被后台杀死的Activity作的一种预防,它的执行时机在2.3以前是在onPause以前,2.3以后,放在了onStop函数以前,也就说Activity失去焦点后,可能会因为内存不足,被回收的状况下,都会去执行onSaveInstanceState。
好比在Activity A 调用startActivity启动Activity B的时候,会首先经过AMS pause Activity A,以后唤起B,在B显示,再stop A,在stop A的时候,须要保存A的现场,由于不可见的Activity都是可能被后台杀死的,好比,在开发者选项中打开不保留活动,就会达到这种效果,在启动另外一个Activity时,上一个Activity的保存流程大概以下
在2.3以后,onSaveInstanceState的时机都放在了onStop以前,看一下FragmentActivity的onSaveInstanceState源码:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
}
复制代码
能够看出,首先就是父类的onSaveInstanceState,主要是保存一些窗口及View的信息,好比ViewPager当前显示的是第几个View等。以后,就是就是经过FragmentManager的saveAllState,来保存FragmentActivity自身的现场-Fragment的一些状态,这些数据是FragmentActivity恢复Framgent所必须的数据,处理很差就会出现上面的那种异常。
OnRestoreInstanceState虽然与onSaveInstanceState是配对实现的,可是其调用却并不是彻底成对的,在Activity跳转或者返回主界面时,onSaveInstanceState是必定会调用的,可是OnRestoreInstanceState却不会,它只有Activity或者App被异常杀死,走恢复流程的时候才会被调用。若是没有被异常杀死,不走Activity的恢复新建流程,也就不会回调OnRestoreInstanceState,简单看一下Activity的加载流程图:
能够看出,OnRestoreInstanceState的调用时机是在onStart以后,在onPostCreate以前。那么正常的建立为何没调用呢?看一下ActivityThread中启动Activity的源码:
private Activity performLaunchActivity(Activi
...
mInstrumentation.callActivityOnCreate(activity, r.state);
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
}
复制代码
能够看出,只有r.state != null的时候,才经过mInstrumentation.callActivityOnRestoreInstanceState回调OnRestoreInstanceState,r.state就是ActivityManagerService经过Binder传给ActivityThread数据,主要用来作场景恢复。以上就是onSaveInstanceState与OnRestoreInstance执行时机的一些分析。下面结合具体的系统View控件来分析一下这两个函数的具体应用:好比ViewPager与FragmentTabHost,这两个空间是主界面最经常使用的控件,内部对后台杀死作了兼容,这也是为何被杀死后,Viewpager在恢复后,能自动定位到上次浏览的位置。
首先看一下ViewPager作的兼容,ViewPager在后台杀死的状况下,仍然能恢复到上次关闭的位置,这也是对体验的一种优化,这其中的原理是什么?以前分析onSaveInstanceState与onRestoreInstanceState的时候,只关注了Fragment的处理,其实还有一些针对Window窗口及View的处理,先看一下onSaveInstanceState针对窗口保存了什么:
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
}
复制代码
PhonwWinow.java
@Override
public Bundle saveHierarchyState() {
Bundle outState = new Bundle();
if (mContentParent == null) {
return outState;
}
SparseArray<Parcelable> states = new SparseArray<Parcelable>();
mContentParent.saveHierarchyState(states);
outState.putSparseParcelableArray(VIEWS_TAG, states);
// save the focused view id
View focusedView = mContentParent.findFocus();
...
outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
// save the panels
if (panelStates.size() > 0) {
outState.putSparseParcelableArray(PANELS_TAG, panelStates);
}
if (mActionBar != null) {
outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
}
return outState;
}
复制代码
Window其实就是PhonwWinow,saveHierarchyState其实就是针对当前窗口中的View保存一些场景信息 ,好比:当前获取焦点的View的id、ActionBar、View的一些状态,固然saveHierarchyState递归遍历全部子View,保存全部须要保存的状态:
ViewGroup.java
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
View c = children[i];
if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
c.dispatchSaveInstanceState(container);
}
}
}
复制代码
可见,该函数首先经过super.dispatchSaveInstanceState保存自身的状态,再递归传递给子View。onSaveInstanceState主要用于获取View须要保存的State,并将自身的ID做为Key,存储到SparseArray states列表中,其实就PhoneWindow的一个列表,这些数据最后会经过Binder保存到ActivityManagerService中去
View.java
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
Parcelable state = onSaveInstanceState();
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onSaveInstanceState()");
}
if (state != null) {
container.put(mID, state);
}
}
}
复制代码
那么针对ViewPager到底存储了什么信息?经过下面的代码很容易看出,其实就是新建个了一个SavedState场景数据,而且将当前的位置mCurItem存进去。
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.position = mCurItem;
if (mAdapter != null) {
ss.adapterState = mAdapter.saveState();
}
return ss;
} 到这里存储的事情基本就完成了。接下来看一下ViewPager的恢复以及onRestoreInstanceState到底作了什么,
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState);
}
}
}
复制代码
从代码能够看出,其实就是获取当时保存的窗口信息,以后经过mWindow.restoreHierarchyState作数据恢复,
@Override
public void restoreHierarchyState(Bundle savedInstanceState) {
if (mContentParent == null) {
return;
}
SparseArray<Parcelable> savedStates
= savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
if (savedStates != null) {
mContentParent.restoreHierarchyState(savedStates);
}
...
if (mActionBar != null) {
...
mActionBar.restoreHierarchyState(actionBarStates);
}
}
复制代码
对于ViewPager会发生什么?从源码很容易看出,其实就是取出SavedState,并获取到异常杀死的时候的位置,以便后续的恢复,
ViewPager.java
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
if (mAdapter != null) {
mAdapter.restoreState(ss.adapterState, ss.loader);
setCurrentItemInternal(ss.position, false, true);
} else {
mRestoredCurItem = ss.position;
mRestoredAdapterState = ss.adapterState;
mRestoredClassLoader = ss.loader;
}
}
复制代码
以上就解释了ViewPager是如何经过onSaveInstanceState与onRestoreInstanceState保存、恢复现场的。若是是ViewPager+FragmentAdapter的使用方式,就同时涉及FragmentActivity的恢复、也牵扯到Viewpager的恢复,其实FragmentAdapter也一样针对后台杀死作了一些兼容,防止重复新建Fragment,看一下FragmentAdapter的源码:
FragmentPagerAdapter.java
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
<!--是否已经新建了Fragment??-->
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
1 若是Activity中存在相应Tag的Fragment,就不要经过getItem新建
if (fragment != null) {
mCurTransaction.attach(fragment);
} else {
2 若是Activity中不存在相应Tag的Fragment,就须要经过getItem新建
fragment = getItem(position);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
FragmentCompat.setMenuVisibility(fragment, false);
FragmentCompat.setUserVisibleHint(fragment, false);
}
return fragment;
}
复制代码
从1与2 能够看出,经过后台恢复,在FragmentActivity的onCreate函数中,会重建Fragment列表,那些被重建的Fragment不会再次经过getItem再次建立,再来看一下类似的控件FragmentTabHost,FragmentTabHost也是主页经常使用的控件,FragmentTabHost也有相应的后台杀死处理机制,从名字就能看出,这个是专门针对Fragment才建立出来的控件。
FragmentTabHost其实跟ViewPager很类似,在onSaveInstanceState执行的时候保存当前位置,并在onRestoreInstanceState恢复postion,并从新赋值给Tabhost,以后FragmentTabHost在onAttachedToWindow时,就能够根据恢复的postion设置当前位置,代码以下:
FragmentTabHost.java
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.curTab = getCurrentTabTag();
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setCurrentTabByTag(ss.curTab);
}
复制代码
在FragmentTabHost执行onAttachedToWindow时候,会首先getCurrentTabTag ,若是是经历了后台杀死,这里获得的值实际上是恢复的SavedState里的值,以后经过doTabChanged切换到响应的Tab,注意这里切换的时候,Fragment因为已经重建了,是不会再次新建的。
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
String currentTab = getCurrentTabTag();
...
ft = doTabChanged(currentTab, ft);
if (ft != null) {
ft.commit();
mFragmentManager.executePendingTransactions();
}
}
复制代码
最简单的方式,可是效果通常:取消系统恢复
好比:针对FragmentActivity ,不重建:
protected void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
savedInstanceState.putParcelable(“android:support:fragments”, null);
}
super.onCreate(savedInstanceState);
}
复制代码
若是是系统的Actvity改为是“android:fragments”,不过这里须要注意:对于ViewPager跟FragmentTabHost不须要额外处理,处理了可能反而有副作用。
针对Window,若是不想让View使用恢复逻辑,在基类的FragmentActivity中覆盖onRestoreInstanceState函数便可。
protected void onRestoreInstanceState(Bundle savedInstanceState) {
}
复制代码
固然以上的作法都是比较粗暴的作法,最好仍是顺着Android的设计,在须要保存现场的地方保存,在须要恢复的地方,去除相应的数据进行恢复。
假设,一个应用被后台杀死,再次从最近的任务列表唤起App时候,系统是如何处理的呢?
首先来看第一个问题,系统如何知道Application被杀死了,Android使用了Linux的oomKiller机制,只是简单的作了个变种,采用分等级的LowmemoryKiller,但这个实际上是内核层面,LowmemoryKiller杀死进程后,如何向用户空间发送通知,并告诉框架层的ActivityMangerService呢?只有AMS在知道App或者Activity是否被杀死后,AMS(ActivityMangerService)才能正确的走重建或者唤起流程,好比,APP死了,可是因为存在须要复活的Service,那么这个时候,进程须要从新启动,这个时候怎么处理的,那么AMS到底是在何时知道App或者Activity被后台杀死了呢?咱们先看一下从最近的任务列表进行唤起的时候,究竟发生了什么。
在系统源码systemUi的包里,有个RecentActivity,这个其实就是最近的任务列表的入口,而其呈现界面是经过RecentsPanelView来展示的,点击最近的App其执行代码以下:
public void handleOnClick(View view) {
ViewHolder holder = (ViewHolder)view.getTag();
TaskDescription ad = holder.taskDescription;
final Context context = view.getContext();
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
Bitmap bm = holder.thumbnailViewImageBitmap;
...
// 关键点 1 若是TaskDescription没有被主动关闭,正常关闭,ad.taskId就是>=0
if (ad.taskId >= 0) {
// This is an active task; it should just go to the foreground.
am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME,
opts);
} else {
Intent intent = ad.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
| Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivityAsUser(intent, opts,
new UserHandle(UserHandle.USER_CURRENT));
}...
}
复制代码
在上面的代码里面,有个判断ad.taskId >= 0,若是知足这个条件,就经过moveTaskToFront唤起APP,那么ad.taskId是如何获取的?recent包里面有各种RecentTasksLoader,这个类就是用来加载最近任务列表的一个Loader,看一下它的源码,主要看一下加载:
@Override
protected Void doInBackground(Void... params) {
// We load in two stages: first, we update progress with just the first screenful
// of items. Then, we update with the rest of the items
final int origPri = Process.getThreadPriority(Process.myTid());
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
final PackageManager pm = mContext.getPackageManager();
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RecentTaskInfo> recentTasks =
am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
....
TaskDescription item = createTaskDescription(recentInfo.id,
recentInfo.persistentId, recentInfo.baseIntent,
recentInfo.origActivity, recentInfo.description);
....
}
复制代码
能够看到,其实就是经过ActivityManger的getRecentTasks向AMS请求最近的任务信息,而后经过createTaskDescription建立TaskDescription,这里传递的recentInfo.id其实就是TaskDescription的taskId,来看一下它的意义:
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) {
...
IPackageManager pm = AppGlobals.getPackageManager();
final int N = mRecentTasks.size();
...
for (int i=0; i<N && maxNum > 0; i++) {
TaskRecord tr = mRecentTasks.get(i);
if (i == 0
|| ((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
|| (tr.intent == null)
|| ((tr.intent.getFlags()
&Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
ActivityManager.RecentTaskInfo rti
= new ActivityManager.RecentTaskInfo();
rti.id = tr.numActivities > 0 ? tr.taskId : -1;
rti.persistentId = tr.taskId;
rti.baseIntent = new Intent(
tr.intent != null ? tr.intent : tr.affinityIntent);
if (!detailed) {
rti.baseIntent.replaceExtras((Bundle)null);
}
复制代码
能够看出RecentTaskInfo的id是由TaskRecord决定的,若是TaskRecord中numActivities > 0就去TaskRecord的Id,不然就取-1,这里的numActivities其实就是TaskRecode中记录的ActivityRecord的数目,更具体的细节能够自行查看ActivityManagerService及ActivityStack,那么这里就容易解释了,只要是存活的APP,或者被LowmemoryKiller杀死的APP,其AMS的ActivityRecord是完整保存的,这也是恢复的依据。对于RecentActivity获取的数据其实就是AMS中的翻版,它也是不知道将要唤起的APP是不是存活的,只要TaskRecord告诉RecentActivity是存货的,那么久直接走唤起流程。也就是经过ActivityManager的moveTaskToFront唤起App,至于后续的工做,就彻底交给AMS来处理。现看一下到这里的流程图:
AMS与客户端的通讯是经过Binder来进行的,而且通讯是”全双工“的,且互为客户端跟服务器,也就说AMS向客户端发命令的时候,AMS是客户端,反之亦然。注意 Binder有个讣告的功能的:若是基于Binder通讯的服务端(S)若是挂掉了,客户端(C)可以收到Binder驱动发送的一份讣告,告知客户端Binder服务挂了,能够把Binder驱动看做是第三方不死邮政机构,专门向客户端发偶像死亡通知。对于APP被异常杀死的状况下,这份讣告是发送给AMS的,AMS在收到通知后,就会针对APP被异常杀死的状况做出整理,这里牵扯到Binder驱动的代码有兴趣能够本身翻一下。之类直接冲讣告接受后端处理逻辑来分析,在AMS源码中,入口其实就是appDiedLocked.
final void appDiedLocked(ProcessRecord app, int pid,
IApplicationThread thread) {
...
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
boolean doLowMem = app.instrumentationClass == null;
关键点1
handleAppDiedLocked(app, false, true);
// 若是是被后台杀了,怎么处理
关键点2
if (doLowMem) {
boolean haveBg = false;
for (int i=mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord rec = mLruProcesses.get(i);
if (rec.thread != null && rec.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
haveBg = true;
break;
}
}
if (!haveBg) {
<!--若是被LowmemoryKiller杀了,就说明内存紧张,这个时候就会通知其余后台APP,当心了,赶忙释放资源-->
EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
long now = SystemClock.uptimeMillis();
for (int i=mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord rec = mLruProcesses.get(i);
if (rec != app && rec.thread != null &&
(rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
rec.lastRequestedGc = 0;
} else {
rec.lastRequestedGc = rec.lastLowMemory;
}
rec.reportLowMemory = true;
rec.lastLowMemory = now;
mProcessesToGc.remove(rec);
addProcessToGcListLocked(rec);
}
}
mHandler.sendEmptyMessage(REPORT_MEM_USAGE);
<!--缩减资源-->
scheduleAppGcsLocked();
}
}
}
...
}
复制代码
先看关键点1:在进程被杀死后,AMS端要选择性清理进程相关信息,清理后,再根据是否是内存低引发的后台杀死,决定是否是须要清理其余后台进程。接着看handleAppDiedLocked如何清理的,这里有重建时的依据:ActivityRecord不清理,可是为它设置个APP未绑定的标识
private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
关键点1
cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
...
关键点2
// Remove this application's activities from active lists. boolean hasVisibleActivities = mMainStack.removeHistoryRecordsForAppLocked(app); app.activities.clear(); ... 关键点3 if (!restarting) { if (!mMainStack.resumeTopActivityLocked(null)) { // If there was nothing to resume, and we are not already // restarting this process, but there is a visible activity that // is hosted by the process... then make sure all visible // activities are running, taking care of restarting this // process. if (hasVisibleActivities) { mMainStack.ensureActivitiesVisibleLocked(null, 0); } } } } 复制代码
看关键点1,cleanUpApplicationRecordLocked,主要负责清理一些Providers,receivers,service之类的信息,而且在清理过程当中根据配置的一些信息决定是否须要重建进程并启动,关键点2 就是关系到唤起流程的判断,关键点3,主要是被杀的进程是不是当前前台进程,若是是,须要重建,并当即显示:先简单看cleanUpApplicationRecordLocked的清理流程
private final void cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index) {
<!--清理service-->
mServices.killServicesLocked(app, allowRestart);
...
boolean restart = false;
<!--清理Providers.-->
if (!app.pubProviders.isEmpty()) {
Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator();
while (it.hasNext()) {
ContentProviderRecord cpr = it.next();
。。。
app.pubProviders.clear();
} ...
<!--清理receivers.-->
// Unregister any receivers.
if (app.receivers.size() > 0) {
Iterator<ReceiverList> it = app.receivers.iterator();
while (it.hasNext()) {
removeReceiverLocked(it.next());
}
app.receivers.clear();
}
... 关键点1,进程是够须要重启,
if (restart && !app.isolated) {
// We have components that still need to be running in the
// process, so re-launch it.
mProcessNames.put(app.processName, app.uid, app);
startProcessLocked(app, "restart", app.processName);
}
...
}
复制代码
从关键点1就能知道,这里是隐藏了进程是否须要重启的逻辑,好比一个Service设置了START_STICKY,被杀后,就须要从新唤起,这里也是流氓软件肆虐的缘由。再接着看mMainStack.removeHistoryRecordsForAppLocked(app),对于直观理解APP重建 ,这句代码处于核心的地位,
boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
...
while (i > 0) {
i--;
ActivityRecord r = (ActivityRecord)mHistory.get(i);
if (r.app == app) {
boolean remove;
<!--关键点1-->
if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
remove = true;
} else if (r.launchCount > 2 &&
remove = true;
} else {
//通常来说,走false
remove = false;
}
<!--关键点2-->
if (remove) {
...
removeActivityFromHistoryLocked(r);
} else {
...
r.app = null;
...
}
return hasVisibleActivities;
}
复制代码
在Activity跳转的时候,准确的说,在stopActivity以前,会保存Activity的现场,这样在AMS端r.haveState==true,也就是说,其ActivityRecord不会被从ActivityStack中移除,同时ActivityRecord的app字段被置空,这里在恢复的时候,是决定resume仍是重建的关键。接着往下看moveTaskToFrontLocked,这个函数在ActivityStack中,主要管理ActivityRecord栈的,全部start的Activity都在ActivityStack中保留一个ActivityRecord,这个也是AMS管理Activiyt的一个依据,最终moveTaskToFrontLocked会调用resumeTopActivityLocked来唤起Activity,AMS获取即将resume的Activity信息的方式主要是经过ActivityRecord,它并不知道Activity自己是否存活,获取以后,AMS在唤醒Activity的环节才知道App或者Activity被杀死,具体看一下resumeTopActivityLocked源码:
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
...
关键点1
if (next.app != null && next.app.thread != null) {
...
} else {
// Whoops, need to restart this activity!
...
startSpecificActivityLocked(next, true, true);
}
return true;
}
复制代码
看关键点1的判断条件,因为已经将ActivityRecord的app字段置空,AMS就知道了这个APP或者Activity被异常杀死过,所以,就会走startSpecificActivityLocked进行重建。 其实仔细想一想很简单,对于主动调用finish的,AMS并不会清理掉ActivitRecord,在唤起APP的时候,若是AMS检测到APP还存活,就走scheduleResumeActivity进行唤起上一个Activity,可是若是APP或者Activity被异常杀死过,那么AMS就经过startSpecificActivityLocked再次将APP重建,而且将最后的Activity重建。
还有一种可能,APP没有被kill,可是Activity被Kill掉了,这个时候会怎么样。首先,Activity的管理是必定经过AMS的,Activity的kill必定是是AMS操刀的,是有记录的,严格来讲,这种状况并不属于后台杀死,由于这属于AMS正常的管理,在可控范围,好比打开了开发者模式中的“不保留活动”,这个时候,虽然会杀死Activity,可是仍然保留了ActivitRecord,因此再唤醒,或者回退的的时候仍然有迹可循,看一下ActivityStack的Destroy回调代码,
final boolean destroyActivityLocked(ActivityRecord r,
boolean removeFromApp, boolean oomAdj, String reason) {
...
if (hadApp) {
...
boolean skipDestroy = false;
try {
关键代码 1
r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
r.configChangeFlags);
...
if (r.finishing && !skipDestroy) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
+ " (destroy requested)");
r.state = ActivityState.DESTROYING;
Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
msg.obj = r;
mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
} else {
关键代码 2
r.state = ActivityState.DESTROYED;
if (DEBUG_APP) Slog.v(TAG, "Clearing app during destroy for activity " + r);
r.app = null;
}
}
return removedFromHistory;
}
复制代码
这里有两个关键啊你单,1是告诉客户端的AcvitityThread清除Activity,2是标记若是AMS本身非正常关闭的Activity,就将ActivityRecord的state设置为ActivityState.DESTROYED,而且清空它的ProcessRecord引用:r.app = null。这里是唤醒时候的一个重要标志,经过这里AMS就能知道Activity被本身异常关闭了,设置ActivityState.DESTROYED是为了让避免后面的清空逻辑。
final void activityDestroyed(IBinder token) {
synchronized (mService) {
final long origId = Binder.clearCallingIdentity();
try {
ActivityRecord r = ActivityRecord.forToken(token);
if (r != null) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
int index = indexOfActivityLocked(r);
if (index >= 0) {
1 <!--这里会是否从history列表移除ActivityRecord-->
if (r.state == ActivityState.DESTROYING) {
cleanUpActivityLocked(r, true, false);
removeActivityFromHistoryLocked(r);
}
}
resumeTopActivityLocked(null);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
复制代码
看代码关键点1,只有r.state == ActivityState.DESTROYING的时候,才会移除ActivityRecord,可是对于不非正常finish的Activity,其状态是不会被设置成ActivityState.DESTROYING,是直接跳过了ActivityState.DESTROYING,被设置成了ActivityState.DESTROYED,因此不会removeActivityFromHistoryLocked,也就是保留了ActivityRecord现场,好像也是依靠异常来区分是不是正常的结束掉Activity。这种状况下是如何启动Activity的呢? 经过上面两点分析,就知道了两个关键点
这样就保证了在resumeTopActivityLocked的时候,走startSpecificActivityLocked分支
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
...
if (next.app != null && next.app.thread != null) {
...
} else {
// Whoops, need to restart this activity!
...
startSpecificActivityLocked(next, true, true);
}
return true;
}
复制代码
到这里,AMS就知道了这个APP或者Activity是否是被异常杀死过,从而,决定是走resume流程仍是restore流程。
App现场的保存流程相对是比较简单的,入口基本就是startActivity的时候,只要是界面的跳转基本都牵扯到Activity的切换跟当前Activity场景的保存:先画个简单的图形,开偏里面讲FragmentActivity的时候,简单说了一些onSaveInstance的执行时机,这里详细看一下AMS是如何管理这些跳转以及场景保存的,模拟场景:Activity A 启动Activity B的时候,这个时候A不可见,可能会被销毁,须要保存A的现场,这个流程是什么样的:简述以下
流程大概是以下样子:
如今咱们经过源码一步一步跟一下,看看AMS在新Activity启动跟旧Activity的保存的时候,到底作了什么:跳过简单的startActivity,直接去AMS中去看
ActivityManagerService
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags,
String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
enforceNotIsolatedCaller("startActivity");
...
return mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
null, null, options, userId);
}
复制代码
ActivityStack
final int startActivityMayWait(IApplicationThread caller, int callingUid,
int res = startActivityLocked(caller, intent, resolvedType,
aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
callingPackage, startFlags, options, componentSpecified, null);
。。。
}
复制代码
这里经过startActivityMayWait启动新的APP,或者新Activity,这里只看简单的,至于从桌面启动App的流程,能够去参考更详细的文章,好比老罗的startActivity流程,大概就是新建ActivityRecord,ProcessRecord之类,并加入AMS中相应的堆栈等,resumeTopActivityLocked是界面切换的统一入口,第一次进来的时候,因为ActivityA还在没有pause,所以须要先暂停ActivityA,这些完成后,
ActivityStack
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
...
<!--必须将当前Resume的Activity设置为pause 而后stop才能继续-->
// We need to start pausing the current activity so the top one
// can be resumed...
if (mResumedActivity != null) {
if (next.app != null && next.app.thread != null) {
mService.updateLruProcessLocked(next.app, false);
}
startPausingLocked(userLeaving, false);
return true;
}
....
}
复制代码
其实这里就是暂停ActivityA,AMS经过Binder告诉ActivityThread须要暂停的ActivityA,ActivityThread完成后再经过Binder通知AMS,AMS会开始resume ActivityB,
private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
if (prev.app != null && prev.app.thread != null) {
...
try {
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags);
复制代码
ActivityThread
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
...
performPauseActivity(token, finished, r.isPreHoneycomb());
...
// Tell the activity manager we have paused.
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
}
}
}
复制代码
AMS收到ActivityA发送过来的pause消息以后,就会唤起ActivityB,入口仍是resumeTopActivityLocked,唤醒B,以后还会A给进一步stop掉,这个时候就牵扯到现场的保存,
ActivityStack
private final void completePauseLocked() {
if (!mService.isSleeping()) {
resumeTopActivityLocked(prev);
} else {
...
} ActivityB如何启动的,本文不关心,只看ActivityA如何保存现场的,ActivityB起来后,会经过ActivityStack的stopActivityLocked去stop ActivityA,
private final void stopActivityLocked(ActivityRecord r) {
...
if (mMainStack) {
r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
...
}
复制代码
回看APP端,看一下ActivityThread中的调用:首先经过callActivityOnSaveInstanceState,将现场保存到Bundle中去,
private void performStopActivityInner(ActivityClientRecord r,
StopInfo info, boolean keepShown, boolean saveState) {
...
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
if (r.state == null) {
state = new Bundle();
state.setAllowFds(false);
mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
r.state = state;
。。。
}
复制代码
以后,经过ActivityManagerNative.getDefault().activityStopped,通知AMS Stop动做完成,在通知的时候,还会将保存的现场数据带过去。
private static class StopInfo implements Runnable {
ActivityClientRecord activity;
Bundle state;
Bitmap thumbnail;
CharSequence description;
@Override public void run() {
// Tell activity manager we have been stopped.
try {
ActivityManagerNative.getDefault().activityStopped(
activity.token, state, thumbnail, description);
} catch (RemoteException ex) {
}
}
}
复制代码
经过上面流程,AMS不只启动了新的Activity,同时也将上一个Activity的现场进行了保存,及时因为种种缘由上一个Actiivity被杀死,在回退,或者从新唤醒的过程当中AMS也能知道如何唤起Activiyt,并恢复。
如今解决两个问题,一、如何保存现场,二、AMS怎么判断知道APP或者Activity是否被异常杀死,那么就剩下最后一个问题了,AMS如何恢复被异常杀死的APP或者Activity呢。
其实在讲解AMS怎么判断知道APP或者Activity是否被异常杀死的时候,就已经涉及了恢复的逻辑,也知道了一旦AMS知道了APP被后台杀死了,那就不是正常的resuem流程了,而是要从新laucher,先来看一下整个APP被干掉的会怎么处理,看resumeTopActivityLocked部分,从上面的分析已知,这种场景下,会由于Binder通讯抛异常走异常分支,以下:
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
....
if (next.app != null && next.app.thread != null) {
if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
...
try {
...
} catch (Exception e) {
// Whoops, need to restart this activity!
这里是知道整个app被杀死的
Slog.i(TAG, "Restarting because process died: " + next);
next.state = lastState;
mResumedActivity = lastResumedActivity;
Slog.i(TAG, "Restarting because process died: " + next);
startSpecificActivityLocked(next, true, false);
return true;
}
复制代码
从上面的代码能够知道,其实就是走startSpecificActivityLocked,这根第一次从桌面唤起APP没多大区别,只是有一点须要注意,那就是这种时候启动的Activity是有上一次的现场数据传递过得去的,由于上次在退到后台的时候,全部Activity界面的现场都是被保存了,而且传递到AMS中去的,那么此次的恢复启动就会将这些数据返回给ActivityThread,再来仔细看一下performLaunchActivity里面关于恢复的特殊处理代码:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
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 app = r.packageInfo.makeApplication(false, mInstrumentation);
...
关键点 1
mInstrumentation.callActivityOnCreate(activity, r.state);
...
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
关键点 1
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
mInstrumentation.callActivityOnPostCreate(activity, r.state);
...
}
复制代码
看一下关键点1跟2,先看关键点1,mInstrumentation.callActivityOnCreate会回调Actiivyt的onCreate,这个函数里面其实主要针对FragmentActivity作一些Fragment恢复的工做,ActivityClientRecord中的r.state是AMS传给APP用来恢复现场的,正常启动的时候,这些都是null。再来看关键点2 ,在r.state != null非空的时候执行mInstrumentation.callActivityOnRestoreInstanceState,这个函数默认主要就是针对Window作一些恢复工做,好比ViewPager恢复以前的显示位置等,也能够用来恢复用户保存数据。
打开开发者模式”不保留活动“,就是这种场景,在上面的分析中,知道,AMS主动异常杀死Activity的时候,将AcitivityRecord的app字段置空,所以resumeTopActivityLocked同整个APP被杀死不一样,会走下面的分支
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
...
if (next.app != null && next.app.thread != null) {
...
} else {
关键点 1 只是重启Activity,可见这里实际上是知道的,进程并没死,
// Whoops, need to restart this activity!
startSpecificActivityLocked(next, true, true);
}
return true;
}
复制代码
虽然不太同样,可是一样走startSpecificActivityLocked流程,只是不新建APP进程,其他的都是同样的,再也不讲解。
主动清除最近任务跟异常杀死的区别:ActivityStack是否正常清除
恢复的时候,为何是倒序恢复:由于这是ActivityStack中的HistoryRecord中栈的顺序,严格按照AMS端来
一句话归纳Android后台杀死恢复原理:Application进程被Kill,但现场被AMS 保存,AMS能根据保存恢复Application现场
LowMemoryKiller(低内存杀手)是Andorid基于oomKiller原理所扩展的一个多层次oomKiller,OOMkiller(Out Of Memory Killer)是在Linux系统没法分配新内存的时候,选择性杀掉进程,到oom的时候,系统可能已经不太稳定,而LowMemoryKiller是一种根据内存阈值级别触发的内存回收的机制,在系统可用内存较低时,就会选择性杀死进程的策略,相对OOMKiller,更加灵活。
Android底层采用的是Linux内核,其进程管理都是基于Linux内核,LowMemoryKiller也相应的放在内核模块,这也意味着用户空间对于后台杀死不可见,就像AMS彻底不知道一个APP是否被后台杀死,只有在AMS唤醒APP的时候,才知道APP是否被LowMemoryKiller杀死过。其实LowmemoryKiller的原理是很清晰的,先看一下总体流程图,再分步分析:
先记住两点 :
Android会尽量长时间地保持应用存活,但为了新建或运行更重要的进程,可能须要移除旧进程来回收内存,在选择要Kill的进程的时候,系统会根据进程的运行状态做出评估,权衡进程的“重要性“,其权衡的依据主要是四大组件。若是须要缩减内存,系统会首先消除重要性最低的进程,而后是重要性略逊的进程,依此类推,以回收系统资源。在Android中,应用进程划分5级(摘自Google文档):Android中APP的重要性层次一共5级:
用户当前操做所必需的进程。若是一个进程知足如下任一条件,即视为前台进程:
一般,在任意给定时间前台进程都为数很少。只有在内存不足以支持它们同时继续运行这一万不得已的状况下,系统才会终止它们。 此时,设备每每已达到内存分页状态,所以须要终止一些前台进程来确保用户界面正常响应。
没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 若是一个进程知足如下任一条件,即视为可见进程:
可见进程被视为是极其重要的进程,除非为了维持全部前台进程同时运行而必须终止,不然系统不会终止这些进程。
正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,可是它们一般在执行一些用户关心的操做(例如,在后台播放音乐或从网络下载数据)。所以,除非内存不足以维持全部前台进程和可见进程同时运行,不然系统会让服务进程保持运行状态。
包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 一般会有不少后台进程在运行,所以它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。若是某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,由于当用户导航回该 Activity 时,Activity会恢复其全部可见状态。
不含任何活动应用组件的进程。保留这种进程的的惟一目的是用做缓存,以缩短下次在其中运行组件所需的启动时间,这就是所谓**热启动 **。为了使系统资源在进程缓存和底层内核缓存之间保持平衡,系统每每会终止这些进程。
根据进程中当前活动组件的重要程度,Android会将进程评定为它可能达到的最高级别。例如,若是某进程托管着服务和可见 Activity,则会将此进程评定为可见进程,而不是服务进程。此外,一个进程的级别可能会因其余进程对它的依赖而有所提升,即服务于另外一进程的进程其级别永远不会低于其所服务的进程。 例如,若是进程 A 中的内容提供程序为进程 B 中的客户端提供服务,或者若是进程 A 中的服务绑定到进程 B 中的组件,则进程 A 始终被视为至少与进程B一样重要。
经过Google文档,对不一样进程的重要程度有了一个直观的认识,下面看一下量化到内存是什么样的呈现形式,这里针对不一样的重要程度,作了进一步的细分,定义了重要级别ADJ,并将优先级存储到内核空间的进程结构体中去,供LowmemoryKiller参考:
以上介绍的目的只有一点:Android的应用进程是有优先级的,它的优先级跟当前是否存在展现界面,以及是否能被用户感知有关,越是被用户感知的的应用优先级越高(系统进程不考虑)。
APP中不少操做均可能会影响进程列表的优先级,好比退到后台、移到前台等,都会潜在的影响进程的优先级,咱们知道Lowmemorykiller是经过遍历内核的进程结构体队列,选择优先级低的杀死,那么APP操做是如何写入到内核空间的呢?Linxu有用户间跟内核空间的区分,不管是APP仍是系统服务,都是运行在用户空间,严格说用户控件的操做是没法直接影响内核空间的,更不用说更改进程的优先级。其实这里是经过了Linux中的一个proc文件体统,proc文件系统能够简单的看可能是内核空间映射成用户能够操做的文件系统,固然不是全部进程都有权利操做,经过proc文件系统,用户空间的进程就可以修改内核空间的数据,好比修改进程的优先级,在Android家族,5.0以前的系统是AMS进程直接修改的,5.0以后,是修改优先级的操做被封装成了一个独立的服务-lmkd,lmkd服务位于用户空间,其做用层次同AMS、WMS相似,就是一个普通的系统服务。咱们先看一下5.0以前的代码,这里仍然用4.3的源码看一下,模拟一个场景,APP只有一个Activity,咱们主动finish掉这个Activity,APP就回到了后台,这里要记住,虽然没有可用的Activity,可是APP自己是没哟死掉的,这就是所谓的热启动,先看下大致的流程:
ActivityManagerService
public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
...
synchronized(this) {
final long origId = Binder.clearCallingIdentity();
boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
...
}
}
复制代码
一开始的流程跟startActivity相似,首先是先暂停当前resume的Activity,其实也就是本身,
final boolean finishActivityLocked(ActivityRecord r, int index, int resultCode,
Intent resultData, String reason, boolean immediate, boolean oomAdj) {
...
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
startPausingLocked(false, false);
}
...
}
复制代码
pause掉当前Activity以后,还须要唤醒上一个Activity,若是当前APP的Activity栈里应经空了,就回退到上一个应用或者桌面程序,唤醒流程就不在讲解了,由于在AMS恢复异常杀死APP的那篇已经说过,这里要说的是唤醒以后对这个即将退回后台的APP的操做,这里注意与startActivity不一样的地方,看下面代码:
ActivityStack
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
if (prev != null) {
if (prev.finishing) {
一、 不一样点
<!--主动finish的时候,走的是这个分支,状态变换的细节请本身查询代码-->
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
}
...
二、相同点
if (!mService.isSleeping()) {
resumeTopActivityLocked(prev);
}
复制代码
看一下上面的两个关键点1跟2,1是同startActivity的completePauseLocked不一样的地方,主动finish的prev.finishing是为true的,所以会执行finishCurrentActivityLocked分支,将当前pause的Activity加到mStoppingActivities队列中去,而且唤醒下一个须要走到到前台的Activity,唤醒后,会继续执行stop:
private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
int index, int mode, boolean oomAdj) {
if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
if (!mStoppingActivities.contains(r)) {
mStoppingActivities.add(r);
...
}
....
return r;
}
...
}
复制代码
让咱们再回到resumeTopActivityLocked继续看,resume以后会回调completeResumeLocked函数,继续执行stop,这个函数经过向Handler发送IDLE_TIMEOUT_MSG消息来回调activityIdleInternal函数,最终执行destroyActivityLocked销毁ActivityRecord,
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
...
if (next.app != null && next.app.thread != null) { ...
try {
。。。
next.app.thread.scheduleResumeActivity(next.appToken,
mService.isNextTransitionForward());
..。
try {
next.visible = true;
completeResumeLocked(next);
}
....
}
复制代码
在销毁Activity的时候,若是当前APP的Activity堆栈为空了,就说明当前Activity没有可见界面了,这个时候就须要动态更新这个APP的优先级,详细代码以下:
final boolean destroyActivityLocked(ActivityRecord r,
boolean removeFromApp, boolean oomAdj, String reason) {
...
if (hadApp) {
if (removeFromApp) {
// 这里动ProcessRecord里面删除,可是没从history删除
int idx = r.app.activities.indexOf(r);
if (idx >= 0) {
r.app.activities.remove(idx);
}
...
if (r.app.activities.size() == 0) {
// No longer have activities, so update oom adj.
mService.updateOomAdjLocked();
...
}
复制代码
最终会调用AMS的updateOomAdjLocked函数去更新进程优先级,在4.3的源码里面,主要是经过Process类的setOomAdj函数来设置优先级:
ActivityManagerService
private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj,
int clientHiddenAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) {
...
计算优先级
computeOomAdjLocked(app, hiddenAdj, clientHiddenAdj, emptyAdj, TOP_APP, false, doingAll);
。。。
<!--若是不相同,设置新的OomAdj-->
if (app.curAdj != app.setAdj) {
if (Process.setOomAdj(app.pid, app.curAdj)) {
...
}
复制代码
Process中setOomAdj是一个native方法,原型在android_util_Process.cpp中
android_util_Process.cpp
jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
jint pid, jint adj)
{
#ifdef HAVE_OOM_ADJ
char text[64];
sprintf(text, "/proc/%d/oom_adj", pid);
int fd = open(text, O_WRONLY);
if (fd >= 0) {
sprintf(text, "%d", adj);
write(fd, text, strlen(text));
close(fd);
}
return true;
#endif
return false;
}
复制代码
能够看到,在native代码里,就是经过proc文件系统修改内核信息,这里就是动态更新进程的优先级oomAdj,以上是针对Android4.3系统的分析,以后会看一下5.0以后的系统是如何实现的。下面是4.3更新oomAdj的流程图,注意红色的执行点:
Android5.0将设置进程优先级的入口封装成了一个独立的服务lmkd服务,AMS再也不直接访问proc文件系统,而是经过lmkd服务来进行设置,从init.rc文件中看到服务的配置。
service lmkd /system/bin/lmkd
class core
critical
socket lmkd seqpacket 0660 system system
复制代码
从配置中能够看出,该服务是经过socket与其余进行进程进行通讯,其实就是AMS经过socket向lmkd服务发送请求,让lmkd去更新进程的优先级,lmkd收到请求后,会经过/proc文件系统去更新内核中的进程优先级。首先看一下5.0中这一块AMS有什么改变,其实大部分流程跟以前4.3源码相似,咱们只看一下不一样地方
ActivityManagerService
private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
ProcessRecord TOP_APP, boolean doingAll, long now) {
...
computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
...
applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
}
private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
long nowElapsed) {
boolean success = true;
if (app.curRawAdj != app.setRawAdj) {
app.setRawAdj = app.curRawAdj;
}
int changes = 0;
不一样点1
if (app.curAdj != app.setAdj) {
ProcessList.setOomAdj(app.pid, app.info.uid, app.curAdj);
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
+ app.adjType);
app.setAdj = app.curAdj;
app.verifiedAdj = ProcessList.INVALID_ADJ;
}
复制代码
从上面的不一样点1能够看出,5.0以后是经过ProcessList类去设置oomAdj,其实这里就是经过socket与LMKD服务进行通讯,向lmkd服务传递给LMK_PROCPRIO命令去更新进程优先级:
public static final void setOomAdj(int pid, int uid, int amt) {
if (amt == UNKNOWN_ADJ)
return;
long start = SystemClock.elapsedRealtime();
ByteBuffer buf = ByteBuffer.allocate(4 * 4);
buf.putInt(LMK_PROCPRIO);
buf.putInt(pid);
buf.putInt(uid);
buf.putInt(amt);
writeLmkd(buf);
long now = SystemClock.elapsedRealtime();
}
private static void writeLmkd(ByteBuffer buf) {
for (int i = 0; i < 3; i++) {
if (sLmkdSocket == null) {
if (openLmkdSocket() == false) {
...
try {
sLmkdOutputStream.write(buf.array(), 0, buf.position());
return;
...
}
复制代码
其实就是openLmkdSocket打开本地socket端口,并将优先级信息发送过去,那么lmkd服务端如何处理的呢,init.rc里配置的服务是在开机时启动的,来看看lmkd服务的入口:main函数
lmkd.c函数
int main(int argc __unused, char **argv __unused) {
struct sched_param param = {
.sched_priority = 1,
};
mlockall(MCL_FUTURE);
sched_setscheduler(0, SCHED_FIFO, ¶m);
if (!init())
mainloop();
ALOGI("exiting");
return 0;
}
复制代码
很简单,打开一个端口,并经过mainloop监听socket,若是有请求到来,就解析命令并执行,刚才传入的LMK_PROCPRIO命令对应的操做就是cmd_procprio,用来更新oomAdj,其更新新机制仍是经过proc文件系统,不信?看下面代码:
static void cmd_procprio(int pid, int uid, int oomadj) {
struct proc *procp;
。。。
仍是利用/proc文件系统进行更新
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
writefilestring(path, val);
。。。
}
复制代码
简单的流程图以下,同4.3不一样的地方
LomemoryKiller属于一个内核驱动模块,主要功能是:在系统内存不足的时候扫描进程队列,找到低优先级(也许说性价比低更合适)的进程并杀死,以达到释放内存的目的。对于驱动程序,入口是__init函数,先看一下这个驱动模块的入口:
static int __init lowmem_init(void)
{
register_shrinker(&lowmem_shrinker);
return 0;
}
复制代码
能够看到在init的时候,LomemoryKiller将本身的lowmem_shrinker入口注册到系统的内存检测模块去,做用就是在内存不足的时候能够被回调,register_shrinker函数是一属于另外一个内存管理模块的函数,若是必定要根下去的话,能够看一下它的定义,其实就是加到一个回调函数队列中去:
void register_shrinker(struct shrinker *shrinker)
{
shrinker->nr = 0;
down_write(&shrinker_rwsem);
list_add_tail(&shrinker->list, &shrinker_list);
up_write(&shrinker_rwsem);
}
复制代码
最后,看一下,当内存不足触发回调的时候,LomemoryKiller是如何找到低优先级进程,并杀死的:入口函数就是init时候注册的lowmem_shrink函数(4.3源码,后面的都有微调但原理大概相似):
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
{
struct task_struct *p;
。。。
关键点1 找到当前的内存对应的阈值
for(i = 0; i < array_size; i++) {
if (other_free < lowmem_minfree[i] &&
other_file < lowmem_minfree[i]) {
min_adj = lowmem_adj[i];
break;
}
}
。。。
关键点2 找到优先级低于这个阈值的进程,并杀死
read_lock(&tasklist_lock);
for_each_process(p) {
if (p->oomkilladj < min_adj || !p->mm)
continue;
tasksize = get_mm_rss(p->mm);
if (tasksize <= 0)
continue;
if (selected) {
if (p->oomkilladj < selected->oomkilladj)
continue;
if (p->oomkilladj == selected->oomkilladj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
}
if(selected != NULL) {
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}
lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem);
read_unlock(&tasklist_lock);
return rem;
}
复制代码
先看关键点1:其实就是肯定当前低内存对应的阈值;关键点2 :找到比该阈值优先级低或者相等,而且内存占用较多的进程(tasksize = get_mm_rss(p->mm)其实就是获取内存占用)),将其杀死。如何杀死的呢?很直接,经过Linux的中的信号量,发送SIGKILL信号直接将进程杀死。到这就分析完了LomemoryKiller内核部分如何工做的。其实很简单,一句话:被动扫描,找到低优先级的进程,杀死。
Binder是一个相似于C/S架构的通讯框架,有时候客户端可能想知道服务端的状态,好比服务端若是挂了,客户端但愿能及时的被通知到,而不是等到再起请求服务端的时候才知道,这种场景其实在互为C/S的时候最经常使用,好比AMS与APP,当APP端进程异常退出的时候,AMS但愿能及时知道,不只仅是清理APP端在AMS中的一些信息,好比ActivityRecord,ServiceRecord等,有时候可能还须要及时恢复一些自启动的Service。Binder实现了一套”死亡讣告”的功能,即:服务端挂了,或者正常退出,Binder驱动会向客户端发送一份讣告,告诉客户端Binder服务挂了。
Binder“讣告”有点采用了相似观察者模式,所以,首先须要将Observer注册到目标对象中,其实就是将Client注册到Binder驱动,未来Binder服务挂掉时候,就能经过驱动去发送。Binder“讣告”发送的入口只有一个:在释放binder设备的时候,在在操做系统中,不管进程是正常退出仍是异常退出,进程所申请的全部资源都会被回收,包括打开的一些设备文件,如Binder字符设备等。在释放的时候,就会调用相应的release函数,“讣告”也就是在这个时候去发送的。所以Binder讣告其实就仅仅包括两部分:注册与通知。
这里拿bindService为例子进行分析,其余场景相似,bindService会首先请求AMS去启动Service,Server端进程在启动时,会调用函数open来打开设备文件/dev/binder,同时将Binder服务实体回传给AMS,AMS再将Binder实体的引用句柄经过Binder通讯传递给Client,也就是在AMS回传给Client的时候,会向Binder驱动注册。其实这也比较好理解,得到了服务端的代理,就应该关心服务端的死活 。当AMS利用IServiceConnection这条binder通讯线路为Client回传Binder服务实体的时候,InnerConnection就会间接的将死亡回调注册到内核:
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service);
}
}
}
复制代码
ServiceDispatcher函数进一步调用 doConnected
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (service != null) {
mDied = false;
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
<!-- 关键点点1-->
service.linkToDeath(info.deathMonitor, 0);
}
}
复制代码
看关键点点1 ,这里的IBinder service实际上是AMS回传的服务代理BinderProxy,linkToDeath是一个Native函数,会进一步调用BpBinde的linkToDeath:
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags){
<!--关键点1-->
IPCThreadState* self = IPCThreadState::self();
self->requestDeathNotification(mHandle, this);
self->flushCommands();
}
复制代码
最终调用IPCThreadState的requestDeathNotification(mHandle, this)向内核发送BC_REQUEST_DEATH_NOTIFICATION请求:
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writeInt32((int32_t)proxy);
return NO_ERROR;
}
复制代码
最后来看一下在内核中,是怎么登记注册的:
int
binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
{
...
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
...
ref = binder_get_ref(proc, target);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
...关键点1
death = kzalloc(sizeof(*death), GFP_KERNEL);
binder_stats.obj_created[BINDER_STAT_DEATH]++;
INIT_LIST_HEAD(&death->work.entry);
death->cookie = cookie;
ref->death = death;
if (ref->node->proc == NULL) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&ref->death->work.entry, &thread->todo);
} else {
list_add_tail(&ref->death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
}
}
}
复制代码
看关键点1 ,其实就是为Client新建binder_ref_death对象,并赋值给binder_ref。在binder驱动中,binder_node节点会记录全部binder_ref,当binder_node所在的进程挂掉后,驱动就能根据这个全局binder_ref列表找到全部Client的binder_ref,并对于设置了死亡回调的Client发送“讣告”,这是由于在binder_get_ref_for_node向Client插入binder_ref的时候,也会插入binder_node的binder_ref列表。
static struct binder_ref *
binder_get_ref_for_node(struct binder_proc *proc, struct binder_node *node)
{
struct rb_node *n;
struct rb_node **p = &proc->refs_by_node.rb_node;
struct rb_node *parent = NULL;
struct binder_ref *ref, *new_ref;
if (node) {
hlist_add_head(&new_ref->node_entry, &node->refs);
}
return new_ref;
}
复制代码
如此,死亡回调入口就被注册到binder内核驱动,以后,等到进程结束要释放binder的时候,就会触发死亡回调。
在调用binder_realease函数来释放相应资源的时候,最终会调用binder_deferred_release函数。该函数会遍历该binder_proc内全部的binder_node节点,并向注册了死亡回调的Client发送讣告,
static void binder_deferred_release(struct binder_proc *proc)
{ ....
if (ref->death) {
death++;
if (list_empty(&ref->death->work.entry)) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
list_add_tail(&ref->death->work.entry, &ref->proc->todo);
// 插入到binder_ref请求进程的binder线程等待队列????? 自然支持binder通讯吗?
// 何时,须要死亡回调,本身也是binder服务?
wake_up_interruptible(&ref->proc->wait);
}
...
}
复制代码
死亡讣告被直接发送到Client端的binder进程todo队列上,这里彷佛也只对于互为C/S通讯的场景有用,当Client的binder线程被唤醒后,就会针对“讣告”作一些清理及善后工做:
static int
binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed, int non_block)
{
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
struct binder_ref_death *death = container_of(w, struct binder_ref_death, work);
uint32_t cmd;
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
else
cmd = BR_DEAD_BINDER;
...
}
复制代码
这里会向用户空间写入一个BR_DEAD_BINDER命令,并返回talkWithDriver函数,返回后,IPCThreadState会继续执行executeCommand,
status_t IPCThreadState::executeCommand(int32_t cmd)
{
// 死亡讣告
case BR_DEAD_BINDER:
{
BpBinder *proxy = (BpBinder*)mIn.readInt32();
<!--关键点1 -->
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writeInt32((int32_t)proxy);
} break; }
复制代码
看关键点1,Obituary直译过来就是讣告,其实就是利用BpBinder发送讣告,待讣告处理结束后,再向Binder驱动发送确认通知。
void BpBinder::sendObituary()
{
ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
this, mHandle, mObitsSent ? "true" : "false");
mAlive = 0;
if (mObitsSent) return;
mLock.lock();
Vector<Obituary>* obits = mObituaries;
if(obits != NULL) {
<!--关键点1-->
IPCThreadState* self = IPCThreadState::self();
self->clearDeathNotification(mHandle, this);
self->flushCommands();
mObituaries = NULL;
}
mObitsSent = 1;
mLock.unlock();
if (obits != NULL) {
const size_t N = obits->size();
for (size_t i=0; i<N; i++) {
reportOneDeath(obits->itemAt(i));
}
delete obits;
}
}
复制代码
看关键点1,这里跟注册相对应,将本身从观察者列表中清除,以后再上报
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp<DeathRecipient> recipient = obit.recipient.promote();
ALOGV("Reporting death to recipient: %p\n", recipient.get());
if (recipient == NULL) return;
recipient->binderDied(this);
}
复制代码
进而调用上层DeathRecipient的回调,作一些清理之类的逻辑。以AMS为例,其binderDied函数就挺复杂,包括了一些数据的清理,甚至还有进程的重建等,不作讨论。