Android O(8.0) Keyguard之启动流程

今天开始梳理SystemUI Keyguard源码
话不多说首先从启动流程开始:

起点是在 SystemUI/src/com/android/systemui/SystemUIService.java

onCreate() -> ((SystemUIApplication) getApplication()).startServicesIfNeeded();

启动SystemUI各个模块
SystemUI/src/com/android/systemui/SystemUIApplication.java

    public void startServicesIfNeeded() {
        startServicesIfNeeded(SERVICES);
    }
    private void startServicesIfNeeded(Class<?>[] services) {
        ..
        startServicesIfNeeded()-> Object newService = SystemUIFactory.getInstance().createInstance(cl);
        ..
        mServices[i].start();
        ..
        if (mBootCompleted) {
            mServices[i].onBootCompleted();
        }
    }

我们这里主要关注KeyguardViewMediator:
SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

    @Override
    public void start() {
        synchronized (this) {
            setupLocked();
        }
        putComponent(KeyguardViewMediator.class, this);
    }
    private void setupLocked() {
        // 获取PowerManager
        mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        // 获取TrustManager
        mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
        // 创建PARTIAL_WAKE_LOCK
        mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
        // 设置WakeLock为不计数机制
        mShowKeyguardWakeLock.setReferenceCounted(false);

        // 注册广播监听
        IntentFilter filter = new IntentFilter();
        filter.addAction(DELAYED_KEYGUARD_ACTION);
        filter.addAction(DELAYED_LOCK_PROFILE_ACTION);
        filter.addAction(Intent.ACTION_SHUTDOWN);
        mContext.registerReceiver(mBroadcastReceiver, filter);

        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback);

        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);

        // KeyguardUpdateMontitor注册一堆广播监听和Listener
        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);

        mLockPatternUtils = new LockPatternUtils(mContext);
        KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());

        // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard
        // is disabled.
        if (mContext.getResources().getBoolean(
                com.android.keyguard.R.bool.config_enableKeyguardService)) {
            setShowingLocked(!shouldWaitForProvisioning()
                    && !mLockPatternUtils.isLockScreenDisabled(
                            KeyguardUpdateMonitor.getCurrentUser()),
                    mSecondaryDisplayShowing, true /* forceCallbacks */);
        }

        // 把statusbar和keyguard关联起来,将mViewMediatorCallback传给mStatusBarKeyguardViewManager
        mStatusBarKeyguardViewManager =
                SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
                        mViewMediatorCallback, mLockPatternUtils);
        final ContentResolver cr = mContext.getContentResolver();

        /*  获取设备可交互状态
            true : 包括dreaming
            false: dozing或asleep 
         * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on}
         * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast
         * whenever the interactive state of the device changes.  For historical reasons,
         * the names of these broadcasts refer to the power state of the screen
         * but they are actually sent in response to changes in the overall interactive
         * state of the device, as described by this method.*/
        mDeviceInteractive = mPM.isInteractive();

        // 加载锁屏解锁音频和音量
        mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
        String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
        if (soundPath != null) {
            mLockSoundId = mLockSounds.load(soundPath, 1);
        }
        ..
        ..
        int lockSoundDefaultAttenuation = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_lockSoundVolumeDb);
        mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);

        // 加载动画 (仅用于获得动画时间偏移量)
        mHideAnimation = AnimationUtils.loadAnimation(mContext,
                com.android.internal.R.anim.lock_screen_behind_enter);

        mWorkLockController = new WorkLockActivityController(mContext);
    }


 

 

关于WakeLock:

android developer文档关于WakeLock的解释

 

WakeLock计数机制(setReferenceCounted):
在创建了PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。这可以通过setReferenceCounted( boolean value) 来指定,默认为计数机制。这两种机制的区别在于,前者无论acquire() 了多少次,只要通过一次release() 即可解锁。而后者正真解锁是在(--count == 0 )的时候,同样当(count == 0) 的时候才会去申请加锁,其他情况下isHeld 状态是不会改变的。所以PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计。


KeyguardService的启动:
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    @Override
    /**
     * Called when the system is done booting to the point where the
     * user can start interacting with it.
     */
    public void systemBooted() {
        bindKeyguard();
        ..
    }

frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java

 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));
     intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
     intent.setComponent(keyguardComponent);

     if (!context.bindServiceAsUser(intent, mKeyguardConnection,
             Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {
     ..
 }

 private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
         // KeyguardServiceWrapper包装类调用KeyguardService的Binder实例
         mKeyguardService = new KeyguardServiceWrapper(mContext,
                 IKeyguardService.Stub.asInterface(service), mCallback);
         if (mKeyguardState.systemIsReady) {
             // If the system is ready, it means keyguard crashed and restarted.
             mKeyguardService.onSystemReady();
             if (mKeyguardState.currentUser != UserHandle.USER_NULL) {
                 // There has been a user switch earlier
                 mKeyguardService.setCurrentUser(mKeyguardState.currentUser);
             }
            // 调用KeyguardService的IPC接口
            ..
            ..
     }

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

在绑定以后,PhoneWindowManager可以调用代理类KeyguardServiceDelegate间接调用KeyguardService的binder接口进行各种锁屏相关状态回调。


初次开机Keyguard showLock流程:

系统启动完成-->PhoneWindowManager.systemReady()-->mKeyguardDelegate.onSystemReady()
-->mKeyguardService.onSystemReady()-->KeyguardService.onSystemReady()

frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java

        @Override // Binder interface
        public void onSystemReady() {
            Trace.beginSection("KeyguardService.mBinder#onSystemReady");
            checkPermission();
            mKeyguardViewMediator.onSystemReady();
            Trace.endSection();
        }

frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

    public void onSystemReady() {
        synchronized (this) {
            if (DEBUG) Log.d(TAG, "onSystemReady");
            mSystemReady = true;
            doKeyguardLocked(null);
            mUpdateMonitor.registerCallback(mUpdateCallback);
        }
        // Most services aren't available until the system reaches the ready state, so we
        // send it here when the device first boots.
        maybeSendUserPresentBroadcast();
    }

    /**
     * Enable the keyguard if the settings are appropriate.
     */
    private void doKeyguardLocked(Bundle options) {
        // 判断是不是安全启动
        if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {
            // Don't show keyguard during half-booted cryptkeeper stage.
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper");
            return;
        }
       ..
       ..

        // if the keyguard is already showing, don't bother
        if (mStatusBarKeyguardViewManager.isShowing()) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
            resetStateLocked();
            return;
        }
       ..
       ..
        if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
        showLocked(options);
    }

    /**
     * Send message to keyguard telling it to show itself
     * @see #handleShow
     */
    private void showLocked(Bundle options) {
        // 持有mShowKeyguardWakeLock
        // ensure we stay awake until we are finished displaying the keyguard
        mShowKeyguardWakeLock.acquire();
        Message msg = mHandler.obtainMessage(SHOW, options);
        mHandler.sendMessage(msg);
        Trace.endSection();
    }

    /**
     * Handle message sent by {@link #showLocked}.
     * @see #SHOW
     */
    private void handleShow(Bundle options) {
        ..
        synchronized (KeyguardViewMediator.this) {
            ..
            setShowingLocked(true);
            //  显示keyguard
            mStatusBarKeyguardViewManager.show(options);
            ..
            // 释放mShowKeyguardWakeLock
            mShowKeyguardWakeLock.release();
        }
        mKeyguardDisplayManager.show();
        Trace.endSection();
    }

接下来就要处理Keyguard绘制的逻辑了,这部分主要是在StatusBarKeyguardViewManager中
调用showBouncerOrKeyguard()方法去显示notification keyguard还是bouncer,在灭屏的情况下,再次亮屏看到的一般是notification keyguard,就是有消息通知、时间之类的那个view,上滑才会显示密码解锁界面,也就是bouncer。接着就会调用showKeyguard(),当然由于还没有绘制内容,所以会进行keyguard的绘制。这里会调用hideBouncer()去隐藏已有的bouncer,因为下次亮屏的时候可能不是原来的锁屏方式。例如原来是PIN解锁,而我们在settings去重置了锁屏为pattern,那下次亮屏就应该显示pattern的view。

    /**
     * Show the keyguard.  Will handle creating and attaching to the view manager
     * lazily.
     */
    public void show(Bundle options) {
        mShowing = true;
        mStatusBarWindowManager.setKeyguardShowing(true);
        mScrimController.abortKeyguardFadingOut();
        reset(true /* hideBouncerWhenShowing */);
    }

    /**
     * Shows the notification keyguard or the bouncer depending on
     * {@link KeyguardBouncer#needsFullscreenBouncer()}.
     */
    protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
        if (mBouncer.needsFullscreenBouncer() && !mDozing) {
            // The keyguard might be showing (already). So we need to hide it.
            mStatusBar.hideKeyguard();
            mBouncer.show(true /* resetSecuritySelection */);
        } else {
            mStatusBar.showKeyguard();
            if (hideBouncerWhenShowing) {
                hideBouncer(false /* destroyView */);
                mBouncer.prepare();
            }
        }
        updateStates();
    }

参考文档:
https://developer.android.google.cn/reference/android/os/PowerManager
https://blog.csdn.net/zhandoushi1982/article/details/8513203
https://blog.csdn.net/qq_28147169/article/details/79467159



作者:汪和呆喵
链接:https://www.jianshu.com/p/89d8e8938a63
來源:简书

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值