美文网首页
WMS:启动窗口的添加与删除

WMS:启动窗口的添加与删除

作者: 81bad73e9053 | 来源:发表于2016-12-05 21:13 被阅读130次

1. 启动窗口的添加

当一个新的Activity启动时系统可能会先显示一个启动窗口,这个窗口会等到Activity的主界面显示出来以后才消失。这个窗口的启动和销毁是由系统来管理的,涉及了AMS和WMS###

当AMS在处理startActivity时,它会调用内部的ActivityStack.startActivityLocked,如果NH>0,说明我们正在切换到一个新的task或者另一个进程,这时就会准备启动一个PreviewWindow,不过会受到以下两个因素的制约

  • SHOW_APP_STARTING_PREVIEW
    ActivityStack中一个Boolean变量,代表是否要启动预览窗口,默认是true
  • doShow
    这个变量默认是true,如果要启动的Activity是一个新的Task中,且设置了FLAG_activity_rest_task_if_needed,那么我们就要在必要的时候执行reset(resetTaskIfNeeded),然后判断这个activity是否在mHistory最顶端,只有这样doShow才会是true,否则不需要添加任何启动窗口

1.1 startActivityLocked

final void startActivityLocked(ActivityRecord r, boolean newTask,
        boolean doResume, boolean keepCurTransition, Bundle options) {
       boolean doShow = true;
        if (newTask) { 
            if ((r.intent.getFlags()
                    &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                resetTaskIfNeededLocked(r, r);
                doShow = topRunningNonDelayedActivityLocked(null) == r;
            }
        }
        if (SHOW_APP_STARTING_PREVIEW && doShow) { 
            ActivityRecord prev = mResumedActivity;
            if (prev != null) { 
                if (prev.task != r.task) {
                    prev = null;
                } 
                else if (prev.nowVisible) {
                    prev = null;
                }
            }
            mWindowManager.setAppStartingWindow(
                    r.appToken, r.packageName, r.theme,
                    mService.compatibilityInfoForPackageLocked(
                            r.info.applicationInfo), r.nonLocalizedLabel,
                    r.labelRes, r.icon, r.logo, r.windowFlags,
                    prev != null ? prev.appToken : null, showStartingIcon);
        }
}  

1.2 setAppStartingWindow

 @Override
public void setAppStartingWindow(IBinder token, String pkg,
        int theme, CompatibilityInfo compatInfo,
        CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
        int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
    

    synchronized(mWindowMap) {
         
        //再次验证是否需要显示启动窗口,因为是activity的启动窗口,那么AppWindowToken一定不能为空
        AppWindowToken wtoken = findAppWindowToken(token);
        if (wtoken == null) { 
            return;
        }

        //屏幕的状态是否允许显示,如果frozen或者disable那么就直接返回
        if (!okToDisplay()) {
            return;
        }
        //用于存储与启动窗口相关的信息,如果这个信息不为空,说明已经处理过启动窗口,这种情况就不要继续往下执行
        if (wtoken.startingData != null) {
            return;
        }

        //加入不存在关联的启动窗口,且调用者又认为没有必要创建一个新的,那么就直接返回
        if (!createIfNeeded) {
            return;
        }


        if (theme != 0) {
        //Activity的主题不能为空
        }

        
        mStartingIconInTransition = true;
        //与启动窗口相关的数据
        wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
                labelRes, icon, logo, windowFlags);
        Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
        //投递消息   msg里包含token,token的startingData包含启动窗口信息
        mH.sendMessageAtFrontOfQueue(m);
    }
}

1.3 消息处理

case ADD_STARTING: {
    //从msg取出token,再从token中取出startingData
    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
    final StartingData sd = wtoken.startingData; 
    if (sd == null) { //数据为空,直接返回
        return;
    } 
    View view = null;
    try {
        //核心
        view = mPolicy.addStartingWindow(
            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo, sd.windowFlags);
    } catch (Exception e) { 

    } 
    if (view != null) {
        boolean abort = false;  
        synchronized(mWindowMap) {
            if (wtoken.removed || wtoken.startingData == null) { 
                if (wtoken.startingWindow != null) { 
                    removeStartingWindowTimeout(wtoken);
                    wtoken.startingWindow = null;
                    wtoken.startingData = null;
                    abort = true;
                }
            } else {
                wtoken.startingView = view;
            } 
        } 
        if (abort) {
            try {
                mPolicy.removeStartingWindow(wtoken.token, view);
            } catch (Exception e) {
                
            }
        }
    }
} 

1.4

  @Override
    public View addStartingWindow(IBinder appToken, String packageName, int theme,
            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
            int icon, int windowFlags) { 
        WindowManager wm = null;
        View view = null;

        try {
            Context context = mContext;  
            //生成一个Window对象
            Window win = PolicyManager.makeNewWindow(context);
            final TypedArray ta = win.getWindowStyle();
            if (ta.getBoolean(
                        com.android.internal.R.styleable.Window_windowDisablePreview, false)
                || ta.getBoolean(
                        com.android.internal.R.styleable.Window_windowShowWallpaper,false)) {
                //如果设置了这两个参数,返回null
                return null;
            }

            Resources r = context.getResources();
            //标题
            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
            //类型
            win.setType(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
            //设置各种窗口标志,启动窗口不接受touch事件
            win.setFlags();
            //设置窗口大小
            win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.MATCH_PARENT);

            final WindowManager.LayoutParams params = win.getAttributes();
            params.token = appToken;
            params.packageName = packageName;
            params.windowAnimations = win.getWindowStyle().getResourceId(
                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
            //params的title
            params.setTitle("Starting " + packageName); 
            wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
            view = win.getDecorView(); 
            //addView
            wm.addView(view, params); 
            return view.getParent() != null ? view : null;
        } catch (WindowManager.BadTokenException e) {
             
        } catch (RuntimeException e) {
            
        } finally { 
                wm.removeViewImmediate(view);
            }
        } 
        return null;
    }
 

和普通Activity窗口一样,我们需要将启动窗口注册到WMS中,然后由WMS在SurfaceFlinger中申请一个Surface来承载UI数据,以使得窗口真正的显示在屏幕上,接下来的步骤就和Activity窗口的添加流程一样

2.启动窗口的销毁

一旦应用程序的主窗口显示出来,与之相关联的启动窗口就会被销毁。

2.1

case REMOVE_STARTING: {
    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
    IBinder token = null;
    View view = null;
    synchronized (mWindowMap) { 
        if (wtoken.startingWindow != null) {
            view = wtoken.startingView;
            token = wtoken.token;
            //清理工作
            wtoken.startingData = null;
            wtoken.startingView = null;
            wtoken.startingWindow = null;
            wtoken.startingDisplayed = false;
        }
    }
    if (view != null) {
        try {
            mPolicy.removeStartingWindow(token, view);
        } catch (Exception e) { 
        }
    }
}

2.2 removeStartingWindow

public void removeStartingWindow(IBinder appToken, View window) { 
    if (window != null) {
        WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        wm.removeView(window);
    }
} 

2.3 removeView

@Override
public void removeView(View view) {
    mGlobal.removeView(view, false);
}


public void removeView(View view, boolean immediate) { 
    synchronized (mLock) {
        int index = findViewLocked(view, true);//找到index
        View curView = mRoots.get(index).getView();//根据index找到view
        removeViewLocked(index, immediate);
        if (curView == view) {
            return;
        } 
    }
}


private void removeViewLocked(int index, boolean immediate) {
    ViewRootImpl root = mRoots.get(index);//根据index找到ViewRootImpl
    View view = root.getView(); 
    //die方法
    boolean deferred = root.die(immediate);
    if (view != null) {
        view.assignParent(null);
        if (deferred) {
            mDyingViews.add(view);
        }
    }
}
 
 
 

2.3

//如果immediate为true,那么直接执行doDie,如果为false通过消息队列还是执行到doDie
boolean die(boolean immediate) { 
    if (immediate && !mIsInTraversal) {
        doDie();
        return false;
    } 
    mHandler.sendEmptyMessage(MSG_DIE);  //            case MSG_DIE:  doDie(); 
    return true;
}



void doDie() {
    checkThread();
    if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
    synchronized (this) {
        if (mRemoved) {
            return;
        }
        mRemoved = true;
        if (mAdded) {
            dispatchDetachedFromWindow();
        }

        if (mAdded && !mFirst) { 
            if (mView != null) {
                int viewVisibility = mView.getVisibility();
                boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                if (mWindowAttributesChanged || viewVisibilityChanged) { 
                    try {
                        //relayoutWindow方法NOTICE。。。
                        if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                            mWindowSession.finishDrawing(mWindow);
                        }
                    } catch (RemoteException e) {
                    }
                } 
                mSurface.release();
            }
        } 
        mAdded = false;//状态位
    }
    WindowManagerGlobal.getInstance().doRemoveView(this);//
}

2.4

void dispatchDetachedFromWindow() {  
    mSurface.release(); 
    try {
        mWindowSession.remove(mWindow);
    } catch (RemoteException e) {
    } 
    unscheduleTraversals();
}
 
public void release() {//释放这个窗口相关的Surface
    synchronized (mLock) {
        if (mNativeObject != 0) {
            nativeRelease(mNativeObject);
            setNativeObjectLocked(0);
        }
    }
}


static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
    sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
    sur->decStrong(&sRefBaseOwner);
} 

//三个数组中的对应对象都删除掉
void doRemoveView(ViewRootImpl root) {
    synchronized (mLock) {
        final int index = mRoots.indexOf(root);
        if (index >= 0) {
            mRoots.remove(index);
            mParams.remove(index);
            final View view = mViews.remove(index);
            mDyingViews.remove(view);
        }
    }
} 

2.5

//WindowState是用来记录窗口状态的,所以当移除窗口的时候WMS中的WindowList里相应的WindowState也是需要更新的
public void remove(IWindow window) {
    mService.removeWindow(this, window);
} 

相关文章

  • Android 解析WindowManagerService

    一、WMS的作用 窗口管理 WMS是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS进...

  • WMS

    WMS 职责/功能 窗口管理WMS 是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由 WM...

  • WMS:启动窗口的添加与删除

    1. 启动窗口的添加 当一个新的Activity启动时系统可能会先显示一个启动窗口,这个窗口会等到Activity...

  • 关于一些Android WMS的解析

    1 、WMS的职责 1.窗口管理WMS是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WM...

  • 谈谈对 WMS 的理解--标准答案

    WMS从内部实现来讲,包含如下功能:1.启动窗口2.窗口的添加与删除3.窗口动画4.窗口大小5.窗口层级6.事件派...

  • Android 重学系列 WMS在Activity启动中的职责

    前言 通过启动窗口为例子,大致上明白了WMS是如何添加,更新,移除窗口的工作原理。本文将会重点聊一聊窗口的大小计算...

  • Android Window 浅析 之一

    1. 概述 窗口管理:窗口的启动、添加和删除,窗口的大小和层级 窗口动画WindowAnimator负责窗口间切换...

  • 15 WMS—启动窗口(StartingWindow)

    一. 概述[http://gityuan.com/2017/01/22/start-activity-wms/#%...

  • WMS:窗口的添加过程

    1.系统窗口的添加过程 1.1例子 1.2 WMS的获取 1.3继承关系 WindowManagerImpl继承自...

  • 系统窗口Toast创建过程

    1.系统窗户的含义 因为在Wms调用addWindow()添加窗口时,会调用WindowManagerPolicy...

网友评论

      本文标题:WMS:启动窗口的添加与删除

      本文链接:https://www.haomeiwen.com/subject/aedlmttx.html