Keyguard分析
2017-06-20 12:37 cascle 阅读(2243) 评论(0) 编辑 收藏 举报从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 24 10 25LOCAL_JAVA_LIBRARIES := SettingsLib 11 26 12 27LOCAL_PRIVILEGED_MODULE := true 13 28 14 29LOCAL_PROGUARD_FLAG_FILES := proguard.flags 15 30 16 31LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res 17 32 18 33include $(BUILD_STATIC_JAVA_LIBRARY) 19 34 20 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 @Override
4 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.class 18 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 167 14 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 172 19 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 @Override 2 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 637 5 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 646 3 647 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 4 648 5 649 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); 6 650 7 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 689 24 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 693 28 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 733 12 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 the 14 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 763 42 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 780 10 781 notifyFinishedGoingToSleep(); 11 782 12 783 if (cameraGestureTriggered) { 13 784 Log.i(TAG, "Camera gesture was triggered, preventing Keyguard locking."); 14 785 15 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 792 22 793 if (mPendingReset) { 23 794 resetStateLocked(); 24 795 mPendingReset = false; 25 796 } 26 797 27 798 if (mPendingLock) { 28 799 doKeyguardLocked(null); 29 800 mPendingLock = false; 30 801 } 31 802 32 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 device 34 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 809 39 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 makes 10 1201 // for an occasional ugly flicker in this situation: 11 1202 // 1) receive a call with the screen on (no keyguard) or make a call 12 1203 // 2) screen times out 13 1204 // 3) user hits key to turn screen back on 14 1205 // instead, we reenable the keyguard when we know the screen is off and the call 15 1206 // ends (see the broadcast receiver below) 16 1207 // TODO: clean this up when we have better support at the window manager level 17 1208 // for apps that wish to be on top of the keyguard 18 1209 return; 19 1210 } 20 1211 21 1212 // if the keyguard is already showing, don't bother 22 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 1218 28 1219 // In split system user mode, we never unlock system user. 29 1220 if (!mustNotUnlockCurrentUser() 30 1221 || !mUpdateMonitor.isDeviceProvisioned()) { 31 1222 32 1223 // if the setup wizard hasn't run yet, don't show 33 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 1231 41 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 1237 47 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 1243 53 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 appears 56 1247 setShowingLocked(false); 57 1248 hideLocked(); 58 1249 mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt(); 59 1250 return; 60 1251 } 61 1252 } 62 1253 63 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方法就会被调用,显示mStatusBarKeyguardViewManager和mKeyguardDisplayManager的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 1642 19 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 1652 29 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 }