Keyguard分析

发布时间:2017-7-1 11:25:49编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Keyguard分析 ",主要涉及到Keyguard分析 方面的内容,对于Keyguard分析 感兴趣的同学可以参考一下。

Keyguard分析

2017-06-20 12:37 by cascle, ... 阅读, ... 评论, 收藏, 编辑

    从Android 6.0开始,位于frameworks/bases/packages/Keyguard的Keyguard开始被编译为一个jar包,被SystemUI静态导入,相当于SystemUI的一个界面,这样Keyguard就可以复用SystemUI里关于通知的那一部分代码,这个在Keyuard的Makefile里可以看到

 1 LOCAL_PATH:= $(call my-dir) 2 17include $(CLEAR_VARS) 3 18 4 19LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files) 5 20 6 21LOCAL_MODULE := Keyguard 7 22 8 23LOCAL_CERTIFICATE := platform 9 2410 25LOCAL_JAVA_LIBRARIES := SettingsLib11 2612 27LOCAL_PRIVILEGED_MODULE := true13 2814 29LOCAL_PROGUARD_FLAG_FILES := proguard.flags15 3016 31LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res17 3218 33include $(BUILD_STATIC_JAVA_LIBRARY)19 3420 35#include $(call all-makefiles-under,$(LOCAL_PATH))

       Keyguard分为两个界面,不用输入密码的一级锁屏界面(SystemUI认为是PhoneStatusBar)与相应源码文件包含Security字样的二级锁屏界面(SystemUI认为是Bouncer)。

       

       一级锁屏界面

       

       二级锁屏界面

       各个部件调用关系是下边这张图

       

       可以看到,Keyguard第一个涉及到的是KeyguardDisplayManager,其由KeyguardViewMediator这个界面中介调用。

       首先,由SystemServer的startSystemUi方法里的StartServiceAsUser连接到SystemUIService。再由SystemUIService(SystemUI/src/com/android/systemui/SystemUIService.java)里的onCreate函数调用(就这一个有用的函数)startServicesIfNeeded方法,开始SystemUI的初始化

1     static final void startSystemUi(Context context) {2         Intent intent = new Intent();3         intent.setComponent(new ComponentName("com.android.systemui",4                     "com.android.systemui.SystemUIService"));5         intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);6         //Slog.d(TAG, "Starting service: " + intent);7         context.startServiceAsUser(intent, UserHandle.SYSTEM);8     }
1 public class SystemUIService extends Service {2 3     @Override4     public void onCreate() {5         super.onCreate();6         ((SystemUIApplication) getApplication()).startServicesIfNeeded();7     }

   

       KeyguardViewMediator是SystemUIApplication名为SERVICES数组里的一员,这个数组的东西都是SystemUI要load的Service的class,这个框架流程在start的时候,调用这些类的start方法,并在bootcompleted的时候调用这些类的onbootcompleted方法。

 1  /** 2 44     * The classes of the stuff to start. 3 45     */ 4 46    private final Class<?>[] SERVICES = new Class[] { 5 47            com.android.systemui.tuner.TunerService.class, 6 48            com.android.systemui.keyguard.KeyguardViewMediator.class, 7 49            com.android.systemui.recents.Recents.class, 8 50            com.android.systemui.volume.VolumeUI.class, 9 51            Divider.class,10 52            com.android.systemui.statusbar.SystemBars.class,11 53            com.android.systemui.usb.StorageNotification.class,12 54            com.android.systemui.power.PowerUI.class,13 55            com.android.systemui.media.RingtonePlayer.class,14 56            com.android.systemui.keyboard.KeyboardUI.class,15 57            com.android.systemui.tv.pip.PipUI.class,16 58            com.android.systemui.shortcut.ShortcutKeyDispatcher.class,17 59            com.android.systemui.VendorServices.class18 60    };

    可以看到,在SystemUIApplication这个类的startServicesIfNeeded里,会依次调用SERVICES里的start函数,这里会先调用com.android.systemui.keyguard.KeyguardViewMediator的start方法

 1 final int N = services.length; 2 156        for (int i=0; i<N; i++) { 3 157            Class<?> cl = services[i]; 4 158            if (DEBUG) Log.d(TAG, "loading: " + cl); 5 159            try { 6 160                Object newService = SystemUIFactory.getInstance().createInstance(cl); 7 161                mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService); 8 162            } catch (IllegalAccessException ex) { 9 163                throw new RuntimeException(ex);10 164            } catch (InstantiationException ex) {11 165                throw new RuntimeException(ex);12 166            }13 16714 168            mServices[i].mContext = this;15 169            mServices[i].mComponents = mComponents;16 170            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);17 171            mServices[i].start();18 17219 173            if (mBootCompleted) {20 174                mServices[i].onBootCompleted();21 175            }22 176        }23 177        mServicesStarted = true;

    

      下面看下KeyguardViewMediator及其start方法

       这个类位于SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java比较长。第三方客户端也可以通过调用KeyguardManager这个类来获取和修改锁屏的信息、状态,这个类是锁屏操作的binder server基础类。

       KeyguardViewMediator是抽象类SystemUI的一个具体实现子类,SystemUI这个类的主要方法是putComponent和getComponent,保存和获取相应类对应的实际组件的映射。还用mContext和mComponents保存相应的SystemUIApplication实例和其中名为component的hashmap。

       KyeguardViewMediator总体负责所有的锁屏状态,并根据状态来决定调用哪些组件。

       KeyguardViewMediator的start方法很简单,初始化锁屏状态,把KeyguardViewMediator的class和KeyguardViewMediator建立映射。

1  @Override2 699    public void start() {3 700        synchronized (this) {4 701            setupLocked();5 702        }6 703        putComponent(KeyguardViewMediator.class, this);7 704    }

        初始化的过程在setupLocked方法里完成,首先获取系统的PowerManagerService,WindowManagerService,TrustManagerService并初始化一把partial wakelock锁

1            mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);2 635        mWM = WindowManagerGlobal.getWindowManagerService();3 636        mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);4 6375 638        mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");6 639        mShowKeyguardWakeLock.setReferenceCounted(false);

          随后注册DELAYED_KEYGUARD_ACTION和DELAYED_LOCK_PROFILE_ACTION这两个Intent的broadcastreceiver

1 641        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));2 642        mContext.registerReceiver(3 643                mBroadcastReceiver, new IntentFilter(DELAYED_LOCK_PROFILE_ACTION));

           然后创建Keyguard包里的KeyguardDisplayManager和KeyguardUpdateMonitor,还有锁屏模式工具类,获取AlarmManagerService,给KeyguardUpdateMonitor设置当前的用户。

1 645        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);2 6463 647        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);4 6485 649        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);6 6507 651        mLockPatternUtils = new LockPatternUtils(mContext);8 652        KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());

            然后设置锁屏状态的变量并调用锁屏状态改变回调函数表,通知TrustManager

1 654        // Assume keyguard is showing (unless it's disabled) until we know for sure...2 655        setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled(3 656                KeyguardUpdateMonitor.getCurrentUser()));4 657        updateInputRestrictedLocked();5 658        mTrustManager.reportKeyguardShowingChanged();

            然后设置视图显示,通过SystemUIFactory获取StatusBarKeyguardViewManager,并把视图中介回调(mViewMediatorCallback)和锁屏模式工具(mLockPatternUtils)传入。

1 660        mStatusBarKeyguardViewManager =2 661                SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,3 662                        mViewMediatorCallback, mLockPatternUtils);

            SystemUIFactory里的code如下

1 84    public StatusBarKeyguardViewManager createStatusBarKeyguardViewManager(Context context,2 85            ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {3 86        return new StatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils);4 87    }

            StatusBarKeyguardViewManager是SystemUI中的一个状态栏组件,是锁屏的视图。

            最后设置锁屏和解锁的声音的文件和音量,获取设备交互状态,加载锁屏隐藏的动画 com.android.internal.R.anim.lock_screen_behind_enter 。

  663        final ContentResolver cr = mContext.getContentResolver();  664  665        mDeviceInteractive = mPM.isInteractive();

1
667 mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0); 2 668 String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND); 3 669 if (soundPath != null) { 4 670 mLockSoundId = mLockSounds.load(soundPath, 1); 5 671 } 6 672 if (soundPath == null || mLockSoundId == 0) { 7 673 Log.w(TAG, "failed to load lock sound from " + soundPath); 8 674 } 9 675 soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);10 676 if (soundPath != null) {11 677 mUnlockSoundId = mLockSounds.load(soundPath, 1);12 678 }13 679 if (soundPath == null || mUnlockSoundId == 0) {14 680 Log.w(TAG, "failed to load unlock sound from " + soundPath);15 681 }16 682 soundPath = Settings.Global.getString(cr, Settings.Global.TRUSTED_SOUND);17 683 if (soundPath != null) {18 684 mTrustedSoundId = mLockSounds.load(soundPath, 1);19 685 }20 686 if (soundPath == null || mTrustedSoundId == 0) {21 687 Log.w(TAG, "failed to load trusted sound from " + soundPath);22 688 }23 68924 690 int lockSoundDefaultAttenuation = mContext.getResources().getInteger(25 691 com.android.internal.R.integer.config_lockSoundVolumeDb);26 692 mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);27 69328 694 mHideAnimation = AnimationUtils.loadAnimation(mContext,29 695 com.android.internal.R.anim.lock_screen_behind_enter);30 696 }

          然后SystemUIApplication会调用  mServices[i].onBootCompleted 方法,会在KeyguardViemMediator的start方法后调用,来发出Intent ACTION_BOOT_COMPLETED,通知其他组件锁屏初始化完成

          上边是锁屏的初始化过程,然后就是锁屏的加载过程。锁屏界面的加载有两个地方,第一个是第一次开机的时候;第二个是在灭屏后,这个时候会预加载锁屏界面加速亮屏显示。

           第一次开机时,,

           在按住Power键灭屏的时候,流程如下

           可以看到,KeyguardViewMediator里有两个回调函数被涉及

           第一个是onStartedGoingToSleep。这个方法里做锁屏的一些预处理,并发出锁屏通知给KeyguardUpdateMonitor(这里的状态太多了)

 1 723    /** 2 724     * Called to let us know the screen was turned off. 3 725     * @param why either {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_USER} or 4 726     *   {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}. 5 727     */ 6 728    public void onStartedGoingToSleep(int why) { 7 729        if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + why + ")"); 8 730        synchronized (this) { 9 731            mDeviceInteractive = false;10 732            mGoingToSleep = true;11 73312 734            // Lock immediately based on setting if secure (user has a pin/pattern/password).13 735            // This also "locks" the device when not secure to provide easy access to the14 736            // camera while preventing unwanted input.15 737            int currentUser = KeyguardUpdateMonitor.getCurrentUser();16 738            final boolean lockImmediately =17 739                    mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)18 740                            || !mLockPatternUtils.isSecure(currentUser);19 741            long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser());20 742            mLockLater = false;21 743            if (mExitSecureCallback != null) {22 744                if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");23 745                try {24 746                    mExitSecureCallback.onKeyguardExitResult(false);25 747                } catch (RemoteException e) {26 748                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);27 749                }28 750                mExitSecureCallback = null;29 751                if (!mExternallyEnabled) {30 752                    hideLocked();31 753                }32 754            } else if (mShowing) {33 755                mPendingReset = true;34 756            } else if ((why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)35 757                    || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {36 758                doKeyguardLaterLocked(timeout);37 759                mLockLater = true;38 760            } else if (!mLockPatternUtils.isLockScreenDisabled(currentUser)) {39 761                mPendingLock = true;40 762            }41 76342 764            if (mPendingLock) {43 765                playSounds(true);44 766            }45 767        }46 768        KeyguardUpdateMonitor.getInstance(mContext).dispatchStartedGoingToSleep(why);47 769        notifyStartedGoingToSleep();48 770    }

           第二个是onFinishedGoingToSleep,可以看到核心方法是doKeyguardLocked和doKeyguardForChildProfilesLocked

 1 772    public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) { 2 773        if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + why + ")"); 3 774        synchronized (this) { 4 775            mDeviceInteractive = false; 5 776            mGoingToSleep = false; 6 777 7 778            resetKeyguardDonePendingLocked(); 8 779            mHideAnimationRun = false; 9 78010 781            notifyFinishedGoingToSleep();11 78212 783            if (cameraGestureTriggered) {13 784                Log.i(TAG, "Camera gesture was triggered, preventing Keyguard locking.");14 78515 786                // Just to make sure, make sure the device is awake.16 787                mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),17 788                        "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");18 789                mPendingLock = false;19 790                mPendingReset = false;20 791            }21 79222 793            if (mPendingReset) {23 794                resetStateLocked();24 795                mPendingReset = false;25 796            }26 79727 798            if (mPendingLock) {28 799                doKeyguardLocked(null);29 800                mPendingLock = false;30 801            }31 80232 803            // We do not have timeout and power button instant lock setting for profile lock.33 804            // So we use the personal setting if there is any. But if there is no device34 805            // we need to make sure we lock it immediately when the screen is off.35 806            if (!mLockLater && !cameraGestureTriggered) {36 807                doKeyguardForChildProfilesLocked();37 808            }38 80939 810        }40 811        KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);41 812    }

         doKeyguardLocked 会先判断要不要锁屏,如果需要,则调用方法showLocked

 1 1192    /** 2 1193     * Enable the keyguard if the settings are appropriate. 3 1194     */ 4 1195    private void doKeyguardLocked(Bundle options) { 5 1196        // if another app is disabling us, don't show 6 1197        if (!mExternallyEnabled) { 7 1198            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); 8 1199 9 1200            // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes10 1201            // for an occasional ugly flicker in this situation:11 1202            // 1) receive a call with the screen on (no keyguard) or make a call12 1203            // 2) screen times out13 1204            // 3) user hits key to turn screen back on14 1205            // instead, we reenable the keyguard when we know the screen is off and the call15 1206            // ends (see the broadcast receiver below)16 1207            // TODO: clean this up when we have better support at the window manager level17 1208            // for apps that wish to be on top of the keyguard18 1209            return;19 1210        }20 121121 1212        // if the keyguard is already showing, don't bother22 1213        if (mStatusBarKeyguardViewManager.isShowing()) {23 1214            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");24 1215            resetStateLocked();25 1216            return;26 1217        }27 121828 1219        // In split system user mode, we never unlock system user.29 1220        if (!mustNotUnlockCurrentUser()30 1221                || !mUpdateMonitor.isDeviceProvisioned()) {31 122232 1223            // if the setup wizard hasn't run yet, don't show33 1224            final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);34 1225            final boolean absent = SubscriptionManager.isValidSubscriptionId(35 1226                    mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.ABSENT));36 1227            final boolean disabled = SubscriptionManager.isValidSubscriptionId(37 1228                    mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));38 1229            final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()39 1230                    || ((absent || disabled) && requireSim);40 123141 1232            if (!lockedOrMissing && shouldWaitForProvisioning()) {42 1233                if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"43 1234                        + " and the sim is not locked or missing");44 1235                return;45 1236            }46 123747 1238            if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())48 1239                    && !lockedOrMissing) {49 1240                if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");50 1241                return;51 1242            }52 124353 1244            if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {54 1245                if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");55 1246                // Without this, settings is not enabled until the lock screen first appears56 1247                setShowingLocked(false);57 1248                hideLocked();58 1249                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();59 1250                return;60 1251            }61 1252        }62 125363 1254        if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");64 1255        showLocked(options);65 1256    }

           showLocked方法会发送SHOW消息

 1 1332    /** 2 1333     * Send message to keyguard telling it to show itself 3 1334     * @see #handleShow 4 1335     */ 5 1336    private void showLocked(Bundle options) { 6 1337        Trace.beginSection("KeyguardViewMediator#showLocked aqcuiring mShowKeyguardWakeLock"); 7 1338        if (DEBUG) Log.d(TAG, "showLocked"); 8 1339        // ensure we stay awake until we are finished displaying the keyguard 9 1340        mShowKeyguardWakeLock.acquire();10 1341        Message msg = mHandler.obtainMessage(SHOW, options);11 1342        mHandler.sendMessage(msg);12 1343        Trace.endSection();13 1344    }

           handleShow方法就会被调用,显示mStatusBarKeyguardViewManagermKeyguardDisplayManager的show方法。

 1 1625    /** 2 1626     * Handle message sent by {@link #showLocked}. 3 1627     * @see #SHOW 4 1628     */ 5 1629    private void handleShow(Bundle options) { 6 1630        Trace.beginSection("KeyguardViewMediator#handleShow"); 7 1631        final int currentUser = KeyguardUpdateMonitor.getCurrentUser(); 8 1632        if (mLockPatternUtils.isSecure(currentUser)) { 9 1633            mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);10 1634        }11 1635        synchronized (KeyguardViewMediator.this) {12 1636            if (!mSystemReady) {13 1637                if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");14 1638                return;15 1639            } else {16 1640                if (DEBUG) Log.d(TAG, "handleShow");17 1641            }18 164219 1643            setShowingLocked(true);20 1644            mStatusBarKeyguardViewManager.show(options);21 1645            mHiding = false;22 1646            mWakeAndUnlocking = false;23 1647            resetKeyguardDonePendingLocked();24 1648            mHideAnimationRun = false;25 1649            updateActivityLockScreenState();26 1650            adjustStatusBarLocked();27 1651            userActivity();28 165229 1653            mShowKeyguardWakeLock.release();30 1654        }31 1655        mKeyguardDisplayManager.show();32 1656        Trace.endSection();33 1657    }

           

           还有一种情况是超时灭屏,与上边的按住Power键灭屏流程基本一样

基本流程分析完了,下面看看Keyguard里的具体每个类

先看KeyguardDisplayManager这个类,这个类是控制手机远程显示的。如果手机远程连接上了电视这样的设备,就先一个一个KeyguardPresentation对话框,是个时钟

 1     protected void updateDisplays(boolean showing) { 2         if (showing) { 3             MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute( 4                     MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); 5             boolean useDisplay = route != null 6                     && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE; 7             Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null; 8  9             if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {10                 if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());11                 mPresentation.dismiss();12                 mPresentation = null;13             }14 15             if (mPresentation == null && presentationDisplay != null) {16                 if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);17                 mPresentation = new KeyguardPresentation(mContext, presentationDisplay,18                         R.style.keyguard_presentation_theme);19                 mPresentation.setOnDismissListener(mOnDismissListener);20                 try {21                     mPresentation.show();22                 } catch (WindowManager.InvalidDisplayException ex) {23                     Slog.w(TAG, "Invalid display:", ex);24                     mPresentation = null;25                 }26             }27         } else {28             if (mPresentation != null) {29                 mPresentation.dismiss();30                 mPresentation = null;31             }32         }33     }


上一篇:使用makecontext实现用户线程【转】 - 张昺华
下一篇:apache配置文件语法错误命令:httpd -t

相关文章

关键词: Keyguard分析

相关评论

本站评论功能暂时取消,后续此功能例行通知。

一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!

二、互相尊重,对自己的言论和行为负责。

最近更新

好贷网好贷款