KeyguardBouncer呈现流程

本文将以开机启动,初次展示PIN码解锁界面为主线,介绍KeyguardService的组织结构并分析密码解锁界面的呈现流程。

一.开机启动到PhoneWindowManager

开机启动init->zygote->systemserver进程
systemserver入口是main(),实例化systemserver对象并调用其run()方法。
在run()方法中,我们此次重点关注startOtherServices();
在startOtherServices()启动了WindowManagerService,
截取部分代码如下:
PhoneWindowManager.WindowManagerService:

private void startOtherServices() {
    WindowManagerService wm = null;
    wm = WindowManagerService.main(context, inputManager,
         mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
         !mFirstBoot, mOnlyCore);//启动服务
    ServiceManager.addService(Context.WINDOW_SERVICE, wm);//注册到ServiceManager,供其他进程调用
        ......
    wm.systemReady();
}

WindowManagerService.systemReady():

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    final WindowManagerPolicy mPolicy = new PhoneWindowManager();//生成PhoneWindowManager实例
    public void systemReady() {
        mPolicy.systemReady();//调用PhoneWindowManager.systemReady()
}  

PhoneWindowManager.systemReady():

public void systemReady() {
    mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
    mKeyguardDelegate.onSystemReady();//实例锁屏代理类并调用其onSystemReady()
    

二.KeyguardService的组织结构

这里先放一张整体的流程图,方便大家查看分析:


KeyguardBouncer呈现流程图.png

KeyguardServiceDelegate.onSystemReady():

protected KeyguardServiceWrapper mKeyguardService;//锁屏服务包装类
public void onSystemReady() {
        if (mKeyguardService != null) {
            mKeyguardService.onSystemReady();
        } else {
            mKeyguardState.systemIsReady = true;
        }
}

KeyguardServiceWrapper.onSystemReady():

private IKeyguardService mService;
public KeyguardServiceWrapper(Context context, IKeyguardService service) {
        mService = service;//IKeyguardService在KeyguardServiceWrapper的构造函数中赋值
        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
}
public void onSystemReady() {
        try {
            mService.onSystemReady();
        } catch (RemoteException e) {
            Slog.w(TAG , "Remote Exception", e);
        }
    }

可以看到KeyguardServiceWrapper对IKeyguardService进行了封装,其方法实现主要是对
IKeyguardService的调用。而IKeyguardService在在KeyguardServiceWrapper的构造函数中赋值。
KeyguardServiceWrapper在哪被实例化的呢?
后头看一下KeyguardServiceDelegate初始化的过程:

/**
* 使用bindService的方式来绑定服务。利用bindService的方式:
* 调用者与服务绑定在一起,调用者退出,服务即终止。
* ps => bind方式绑定服务,服务的执行顺序为:
* onCreate()->onBind()->onUnbind()->onDestroy()
*/
 public void bindService(Context context) {
        Intent intent = new Intent();
        final Resources resources = context.getApplicationContext().getResources();

        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
                resources.getString(com.android.internal.R.string.config_keyguardComponent));
        //config_keyguardComponent->com.android.systemui/com.android.systemui.keyguard.KeyguardService
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        intent.setComponent(keyguardComponent);
        
        //这里将KeyguardServiceDelegate与KeyguardService绑定到了一起。
        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                Context.BIND_AUTO_CREATE, mScrimHandler, UserHandle.SYSTEM)) {
            Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
            mKeyguardState.showing = false;
            mKeyguardState.showingAndNotOccluded = false;
            mKeyguardState.secure = false;
            synchronized (mKeyguardState) {
                // TODO: Fix synchronisation model in this class. The other state in this class
                // is at least self-healing but a race condition here can lead to the scrim being
                // stuck on keyguard-less devices.
                mKeyguardState.deviceHasKeyguard = false;
                hideScrim();
            }
        } else {
            if (DEBUG) Log.v(TAG, "*** Keyguard started");
        }
    }

    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
            //通过onServiceConnected()拿到KeyguardService的Binder代理对象,并创建KeyguardService包装类
            //实例化KeyguardServiceWrapper
            mKeyguardService = new KeyguardServiceWrapper(mContext,
                    IKeyguardService.Stub.asInterface(service));
           ......
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
            mKeyguardService = null;
        }
    };

可以看到KeyguardServiceDelegate去绑定KeyguardService,KeyguardServiceDelegate就相当于一个客户端,而
KeyguardService即为服务端。
看一下KeyguardService:

public class KeyguardService extends Service {
    static final String TAG = "KeyguardService";
    static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;

    private KeyguardViewMediator mKeyguardViewMediator;

    @Override
    public void onCreate() {
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
        mKeyguardViewMediator =
                ((SystemUIApplication) getApplication()).getComponent(KeyguardViewMediator.class);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;//此返回值将返回到KeyguardServiceDelegate的onServiceConnected(),通过这个Binder对象,客户端与服务端才能连接起来
    }
    
    
    //mBinder实例化,重写相关接口方法
    private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
    
        @Override // Binder interface
        public void onSystemReady() {
            checkPermission();
            mKeyguardViewMediator.onSystemReady();//实际KeyguardService调用KeyguardViewMediator的对应方法
        }
        ......
    }
}

KeyguardViewMediator.onSystemReady()

public void onSystemReady() {
        synchronized (this) {
            ......
            doKeyguardLocked(null);//锁屏调起的真正入口,进行锁屏预处理工作
            ......
        }
}

三.KeyguardBouncer呈现流程

上文调用如下:
PhoneWindowManager.systemReady()->KeyguardServiceDelegate.onSystemReady()
->KeyguardServiceWrapper.onSystemReady()->KeyguardService.onSystemReady()->
KeyguardViewMediator.onSystemReady().

KeyguardViewMediator.doKeyguardLocked():

private void doKeyguardLocked(Bundle options) {
        //如果其他应用阻止我们显示,那么就不显示。。例如:接打电话
        if (!mExternallyEnabled || PowerOffAlarmManager.isAlarmBoot()) {
            return;
        }
        
        //如果锁屏正在显示,那我们就不去显示
        if (mStatusBarKeyguardViewManager.isShowing()) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
            resetStateLocked();
            if (DEBUG) {
                Log.d(TAG, "doKeyguard: not showing because it is already showing");
            }
            return;
        }

        ......
        //经过上述判断后,再去显示锁屏
        showLocked(options);
    }

KeyguardViewMediator.showLocked()

private void showLocked(Bundle options) {
        ......
        //获取锁屏锁,不让cpu进入休眠,以完整的展示锁屏
        mShowKeyguardWakeLock.acquire();
        Message msg = mHandler.obtainMessage(SHOW, options);
        mHandler.sendMessage(msg);//发送SHOW消息
}

 public void handleMessage(Message msg) {
            switch (msg.what) {
                case SHOW:
                    handleShow((Bundle) msg.obj);
                    break;

KeyguardViewMediator.handleShow()

private void handleShow(Bundle options) {
        mStatusBarKeyguardViewManager =
                SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
                        mViewMediatorCallback, mLockPatternUtils);
        synchronized (KeyguardViewMediator.this) {
            ......
            mStatusBarKeyguardViewManager.show(options);//主要是调用了这里
            ......

StatusBarKeyguardViewManager.show():

public void show(Bundle options) {
        ......
        reset();
}

StatusBarKeyguardViewManager.reset():

public void reset() {
    if (mShowing) {
        if (mOccluded) {//是否有遮挡物,如果有就隐藏锁屏,没有则判断显示锁屏还是密码解锁界面
                mPhoneStatusBar.hideKeyguard();
                mPhoneStatusBar.stopWaitingForKeyguardExit();
                mBouncer.hide(false /* destroyView */);
            } else {
                showBouncerOrKeyguard();//判断显示锁屏还是密码解锁界面
            }
       KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
       updateStates();
    }
}

StatusBarKeyguardViewManager.showBouncerOrKeyguard():

protected void showBouncerOrKeyguard() {
    if (mBouncer.needsFullscreenBouncer()) {//是否需要显示密码锁屏界面
            // The keyguard might be showing (already). So we need to hide it.
        mPhoneStatusBar.hideKeyguard();//隐藏锁屏,显示密码解锁界面
        mBouncer.show(true /* resetSecuritySelection */);
    } else {
        mPhoneStatusBar.showKeyguard();//显示锁屏,隐藏密码解锁界面
        mBouncer.hide(false /* destroyView */);
        mBouncer.prepare();
    }
}

Bouncer.needsFullscreenBouncer():

public boolean needsFullscreenBouncer() {
        ensureView();
        SecurityMode mode = mSecurityModel.getSecurityMode();//获得当前是哪一种安全模式
        return mode == SecurityMode.SimPinPukMe1
                || mode == SecurityMode.SimPinPukMe2
                || mode == SecurityMode.SimPinPukMe3
                || mode == SecurityMode.SimPinPukMe4
                || mode == SecurityMode.AntiTheft
                || mode == SecurityMode.AlarmBoot;
}

KeyguardSecurityModel.getSecurityMode():

public SecurityMode getSecurityMode() { 
        KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);

        SecurityMode mode = SecurityMode.None;

        if (PowerOffAlarmManager.isAlarmBoot()) { /// M: add for power-off alarm
            mode = SecurityMode.AlarmBoot;
        } else {
            //检查当前sim卡的Pin/Puk/Me是否均已解锁
            for (int i = 0; i < KeyguardUtils.getNumOfPhone(); i++) {
                if (isPinPukOrMeRequiredOfPhoneId(i)) {//判断此卡是否需要进行密码解锁
                    if (0 == i) {
                        mode = SecurityMode.SimPinPukMe1;
                    } else if (1 == i) {
                        mode = SecurityMode.SimPinPukMe2;
                    } else if (2 == i) {
                        mode = SecurityMode.SimPinPukMe3;
                    } else if (3 == i) {
                        mode = SecurityMode.SimPinPukMe4;
                    }
                    break;
                }
            }
        }
        //是否需要显示防盗保护
        if (AntiTheftManager.isAntiTheftPriorToSecMode(mode)) {
            Log.d("KeyguardSecurityModel", "should show AntiTheft!") ;
            mode = SecurityMode.AntiTheft;
        }
        //如果当前安全模式不是sim卡的Pin/Puk/Me也不是防盗保护,则查看是PIN码,密码,还是手势
        if (mode == SecurityMode.None) {
            final int security = mLockPatternUtils.getActivePasswordQuality(
                    KeyguardUpdateMonitor.getCurrentUser());
            switch (security) {
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
                    return SecurityMode.PIN;

                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
                    return SecurityMode.Password;

                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                    return SecurityMode.Pattern;
                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
                    return SecurityMode.None;

                default:
                    throw new IllegalStateException("Unknown security quality:" + security);
            }
        }

        Log.d(TAG, "getSecurityMode() - mode = " + mode);
        return mode;
    }

本文以sim卡1的Pin码解锁为例,则getSecurityMode返回SecurityMode.SimPinPukMe1。至needsFullscreenBouncer(),
再至showBouncerOrKeyguard(),此时mBouncer.needsFullscreenBouncer()条件为真,隐藏锁屏,显示bouncer.
mBouncer.show(true /* resetSecuritySelection */);//重置安全选择

public void show(boolean resetSecuritySelection) {
    ......
    show(resetSecuritySelection, false) ;
}

public void show(boolean resetSecuritySelection, boolean authenticated) {
        ......
        if (resetSecuritySelection) {//此时resetSecuritySelection为true
            // showPrimarySecurityScreen() updates the current security method. This is needed in
            // case we are already showing and the current security method changed.
            mKeyguardView.showPrimarySecurityScreen();
        }
        ......
}
    
public void showPrimarySecurityScreen() {
      mSecurityContainer.showPrimarySecurityScreen(false);
}

KeyguardSecurityContainer.showPrimarySecurityScreen();

void showPrimarySecurityScreen(boolean turningOff) {
        //获取当前安全模式,上文分析过
        SecurityMode securityMode = mSecurityModel.getSecurityMode();
        ......
        showSecurityScreen(securityMode);
    }

KeyguardSecurityContainer.showSecurityScreen:

//初次启动时mCurrentSecuritySelection为SecurityMode.Invalid
private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;

private void showSecurityScreen(SecurityMode securityMode) {
        //判断此参数安全模式是否与当前安全模式相同,如果相同则直接返回。
        if ((securityMode == mCurrentSecuritySelection)
                && (securityMode != SecurityMode.AntiTheft)) {
            return;
        }
        //如果不同,则通知安全模式的改变
        VoiceWakeupManager.getInstance().notifySecurityModeChange(
                mCurrentSecuritySelection, securityMode);
        
        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
       
        KeyguardSecurityView newView = getSecurityView(securityMode);//关键方法,根据安全模式获得对应的view

        ......
        //设置相关回调
        if (securityMode != SecurityMode.None) {
            newView.setKeyguardCallback(mCallback);
            newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
        }

        final int childCount = mSecurityViewFlipper.getChildCount();
        //寻找当前安全模式对应的view,并进行展示。(此时PIN码解锁解锁已在getSecurityView()中添加至mSecurityViewFlipper)
        //到这里view的展示也到达了本文流程的终点。
        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
        for (int i = 0; i < childCount; i++) {
            if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
                mSecurityViewFlipper.setDisplayedChild(i);
                break;
            }
        }
        //更新当前的安全选择
        mCurrentSecuritySelection = securityMode;
        ......
}

KeyguardSecurityContainer.getSecurityView()

private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);//获取安全模式对应的view id
        KeyguardSecurityView view = null;
        final int children = mSecurityViewFlipper.getChildCount();
        //从mSecurityViewFlipper中取出此安全模式对应view id的view,按照开机初次抵达这里的情况,此时获取的view为null
        for (int child = 0; child < children; child++) {
            if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
                view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
                break;
            }
        }
        //根据安全模式获得对应的layoutId
        int layoutId = getLayoutIdFor(securityMode);
        //如果mSecurityViewFlipper还没有此view并且存在此安全模式对应的layoutId
        if (view == null && layoutId != 0) {
            //inflater Layout
            final LayoutInflater inflater = LayoutInflater.from(mContext);
            View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);//view在这里被绘制,进行各项初始化。
            view = (KeyguardSecurityView) v;//
            //如果是KeyguardSimPinPukMeView则需要设置phoneid,KeyguardSimPinPukMeView将根据此phoneid展示对应资源
            if (view instanceof KeyguardSimPinPukMeView) {
                KeyguardSimPinPukMeView pinPukView = (KeyguardSimPinPukMeView) view;
                final int phoneId = mSecurityModel.getPhoneIdUsingSecurityMode(securityMode);
                pinPukView.setPhoneId(phoneId);
            }
            //将此view添加入mSecurityViewFlipper中
            mSecurityViewFlipper.addView(v);//在这里添加view至mSecurityViewFlipper
            updateSecurityView(v); //更新KeyguardSecurityView
        }
        return view;
}


private int getSecurityViewIdForMode(SecurityMode securityMode) {
        switch (securityMode) {
            case Pattern: return R.id.keyguard_pattern_view;
            case PIN: return R.id.keyguard_pin_view;
            case Password: return R.id.keyguard_password_view;
            case SimPinPukMe1:
            case SimPinPukMe2:
            case SimPinPukMe3:
            case SimPinPukMe4:
                return R.id.keyguard_sim_pin_puk_me_view ;
        }
        return 0;
}


protected int getLayoutIdFor(SecurityMode securityMode) {
        switch (securityMode) {
            case Pattern: return R.layout.keyguard_pattern_view;//手势
            case PIN: return R.layout.keyguard_pin_view;//PIN码
            case Password: return R.layout.keyguard_password_view;//密码解锁

            case SimPinPukMe1:
            case SimPinPukMe2:
            case SimPinPukMe3:
            case SimPinPukMe4:
                return R.layout.mtk_keyguard_sim_pin_puk_me_view;//sim_pin_puk_me
            
            default:
                return 0;
        }
}

到这里,view展示,其启动流程也到此结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容