diff options
10 files changed, 706 insertions, 9 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 00be9fe564da..376118c8122c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1529,6 +1529,11 @@ factory reset. --> <bool name="config_enableCredentialFactoryResetProtection">true</bool> + <!-- If true, then work around broken Weaver HALs that don't work reliably before the device has + fully booted. Setting this to true weakens a security feature; it should be done only when + necessary, though it is still better than not using Weaver at all. --> + <bool name="config_disableWeaverOnUnsecuredUsers">false</bool> + <!-- Control the behavior when the user long presses the home button. 0 - Nothing 1 - Launch all apps intent diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 06a4d550b204..9ab8ad83480e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3958,6 +3958,7 @@ <java-symbol type="string" name="foreground_service_multiple_separator" /> <java-symbol type="bool" name="config_enableCredentialFactoryResetProtection" /> + <java-symbol type="bool" name="config_disableWeaverOnUnsecuredUsers" /> <!-- ETWS primary messages --> <java-symbol type="string" name="etws_primary_default_message_earthquake" /> diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml new file mode 100644 index 000000000000..8a77d88a7e83 --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2024, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License") +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- This is the screen that shows the 9 circle unlock widget and instructs + the user how to unlock their device, or make an emergency call. This + is the landscape layout. --> +<com.android.keyguard.KeyguardPatternView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/res-auto" + android:id="@+id/keyguard_pattern_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center_horizontal|bottom" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="2" + android:clipChildren="false" + android:clipToPadding="false" + android:layoutDirection="ltr" + android:orientation="vertical"> + + <include layout="@layout/keyguard_bouncer_message_area"/> + + <com.android.systemui.bouncer.ui.BouncerMessageView + android:id="@+id/bouncer_message_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + androidprv:layout_constraintBottom_toTopOf="@+id/lockPatternView" + androidprv:layout_constraintTop_toTopOf="parent" + androidprv:layout_constraintVertical_chainStyle="packed" /> + + <include + android:id="@+id/keyguard_selector_fade_container" + layout="@layout/keyguard_eca" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin" + android:layout_marginTop="@dimen/keyguard_eca_top_margin" + android:gravity="center_horizontal" + android:orientation="vertical" + androidprv:layout_constraintBottom_toBottomOf="parent" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/pattern_container" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="3" + android:clipChildren="false" + android:clipToPadding="false" + android:layoutDirection="ltr" + android:orientation="vertical"> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/pattern_top_guideline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + androidprv:layout_constraintGuide_percent="0" /> + + <com.android.internal.widget.LockPatternView + android:id="@+id/lockPatternView" + android:layout_width="0dp" + android:layout_height="0dp" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal" + androidprv:layout_constraintDimensionRatio="1.0" + androidprv:layout_constraintVertical_bias="1.0" + androidprv:layout_constraintLeft_toLeftOf="parent" + androidprv:layout_constraintRight_toRightOf="parent" + androidprv:layout_constraintBottom_toBottomOf="parent" + androidprv:layout_constraintTop_toBottomOf="@id/pattern_top_guideline"/> + + </androidx.constraintlayout.widget.ConstraintLayout> +</com.android.keyguard.KeyguardPatternView> diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml new file mode 100644 index 000000000000..4b8b63fe9396 --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2024, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License") +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. --> +<com.android.keyguard.KeyguardSimPinView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/res-auto" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/keyguard_sim_pin_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center_horizontal|bottom" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="2" + android:clipChildren="false" + android:clipToPadding="false" + android:layoutDirection="ltr" + android:orientation="vertical"> + + <include layout="@layout/keyguard_bouncer_message_area"/> + + <ImageView + android:id="@+id/keyguard_sim" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_marginBottom="3dp" + android:src="@drawable/ic_lockscreen_sim" + androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area" + androidprv:layout_constraintLeft_toLeftOf="parent" + androidprv:layout_constraintRight_toRightOf="parent" + app:tint="@color/background_protected"/> + + <include + android:id="@+id/keyguard_esim_area" + layout="@layout/keyguard_esim_area" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + androidprv:layout_constraintLeft_toLeftOf="parent" + androidprv:layout_constraintRight_toRightOf="parent" + androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/> + + <com.android.keyguard.AlphaOptimizedRelativeLayout + android:id="@+id/pin_entry_area" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom" + androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container"> + + <com.android.keyguard.PasswordTextView + android:id="@+id/simPinEntry" + style="@style/Widget.TextView.Password" + android:layout_width="@dimen/keyguard_security_width" + android:layout_height="@dimen/keyguard_password_height" + android:layout_centerHorizontal="true" + android:layout_marginRight="72dp" + android:contentDescription="@string/keyguard_accessibility_sim_pin_area" + androidprv:scaledTextSize="@integer/scaled_password_text_size" /> + </com.android.keyguard.AlphaOptimizedRelativeLayout> + + <include + android:id="@+id/keyguard_selector_fade_container" + layout="@layout/keyguard_eca" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin" + android:layout_marginTop="@dimen/keyguard_eca_top_margin" + android:gravity="center_horizontal" + android:orientation="vertical" + androidprv:layout_constraintBottom_toBottomOf="parent"/> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/sim_pin_container" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="3" + android:clipChildren="false" + android:clipToPadding="false" + android:layoutDirection="ltr" + android:orientation="vertical"> + + <androidx.constraintlayout.helper.widget.Flow + android:id="@+id/flow1" + android:layout_width="0dp" + android:layout_height="0dp" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal" + androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter" + androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end" + androidprv:flow_horizontalStyle="packed" + androidprv:flow_maxElementsWrap="3" + androidprv:flow_verticalBias="0.5" + androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom" + androidprv:flow_verticalStyle="packed" + androidprv:flow_wrapMode="aligned" + androidprv:layout_constraintLeft_toLeftOf="parent" + androidprv:layout_constraintRight_toRightOf="parent" + androidprv:layout_constraintTop_toTopOf="parent" + androidprv:layout_constraintBottom_toBottomOf="parent"/> + + <com.android.keyguard.NumPadButton + android:id="@+id/delete_button" + style="@style/NumPadKey.Delete" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key0" + android:contentDescription="@string/keyboardview_keycode_delete" /> + + <com.android.keyguard.NumPadButton + android:id="@+id/key_enter" + style="@style/NumPadKey.Enter" + android:layout_width="0dp" + android:layout_height="0dp" + android:contentDescription="@string/keyboardview_keycode_enter" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key1" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key2" + androidprv:digit="1" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key2" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key3" + androidprv:digit="2" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key3" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key4" + androidprv:digit="3" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key4" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key5" + androidprv:digit="4" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key5" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key6" + androidprv:digit="5" + androidprv:textView="@+id/simPinEntry" /> + + + <com.android.keyguard.NumPadKey + android:id="@+id/key6" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key7" + androidprv:digit="6" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key7" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key8" + androidprv:digit="7" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key8" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key9" + androidprv:digit="8" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key9" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/delete_button" + androidprv:digit="9" + androidprv:textView="@+id/simPinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key0" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key_enter" + androidprv:digit="0" + androidprv:textView="@+id/simPinEntry" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</com.android.keyguard.KeyguardSimPinView> diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml new file mode 100644 index 000000000000..9012856c7bb4 --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml @@ -0,0 +1,223 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2024, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License") +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<!-- This is the SIM PUK view that allows the user to recover their device by entering the + carrier-provided PUK code and entering a new SIM PIN for it. --> +<com.android.keyguard.KeyguardSimPukView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/res-auto" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/keyguard_sim_puk_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center_horizontal|bottom" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="2" + android:clipChildren="false" + android:clipToPadding="false" + android:layoutDirection="ltr" + android:orientation="vertical"> + + <include layout="@layout/keyguard_bouncer_message_area"/> + + <ImageView + android:id="@+id/keyguard_sim" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_marginBottom="3dp" + android:src="@drawable/ic_lockscreen_sim" + androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area" + androidprv:layout_constraintLeft_toLeftOf="parent" + androidprv:layout_constraintRight_toRightOf="parent" + app:tint="@color/background_protected"/> + + <include + android:id="@+id/keyguard_esim_area" + layout="@layout/keyguard_esim_area" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + androidprv:layout_constraintLeft_toLeftOf="parent" + androidprv:layout_constraintRight_toRightOf="parent" + androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/> + + <com.android.keyguard.AlphaOptimizedRelativeLayout + android:id="@+id/pin_entry_area" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom" + androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container"> + + <com.android.keyguard.PasswordTextView + android:id="@+id/pukEntry" + style="@style/Widget.TextView.Password" + android:layout_width="@dimen/keyguard_security_width" + android:layout_height="@dimen/keyguard_password_height" + android:layout_centerHorizontal="true" + android:layout_marginRight="72dp" + android:contentDescription="@string/keyguard_accessibility_sim_pin_area" + androidprv:scaledTextSize="@integer/scaled_password_text_size" /> + </com.android.keyguard.AlphaOptimizedRelativeLayout> + + <include + android:id="@+id/keyguard_selector_fade_container" + layout="@layout/keyguard_eca" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin" + android:layout_marginTop="@dimen/keyguard_eca_top_margin" + android:gravity="center_horizontal" + android:orientation="vertical" + androidprv:layout_constraintBottom_toBottomOf="parent"/> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/sim_puk_container" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="3" + android:clipChildren="false" + android:clipToPadding="false" + android:layoutDirection="ltr" + android:orientation="vertical"> + + <androidx.constraintlayout.helper.widget.Flow + android:id="@+id/flow1" + android:layout_width="0dp" + android:layout_height="0dp" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal" + androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter" + androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end" + androidprv:flow_horizontalStyle="packed" + androidprv:flow_maxElementsWrap="3" + androidprv:flow_verticalBias="0.5" + androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom" + androidprv:flow_verticalStyle="packed" + androidprv:flow_wrapMode="aligned" + androidprv:layout_constraintLeft_toLeftOf="parent" + androidprv:layout_constraintRight_toRightOf="parent" + androidprv:layout_constraintTop_toTopOf="parent" + androidprv:layout_constraintBottom_toBottomOf="parent"/> + + <com.android.keyguard.NumPadButton + android:id="@+id/delete_button" + style="@style/NumPadKey.Delete" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key0" + android:contentDescription="@string/keyboardview_keycode_delete" /> + + <com.android.keyguard.NumPadButton + android:id="@+id/key_enter" + style="@style/NumPadKey.Enter" + android:layout_width="0dp" + android:layout_height="0dp" + android:contentDescription="@string/keyboardview_keycode_enter" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key1" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key2" + androidprv:digit="1" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key2" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key3" + androidprv:digit="2" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key3" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key4" + androidprv:digit="3" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key4" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key5" + androidprv:digit="4" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key5" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key6" + androidprv:digit="5" + androidprv:textView="@+id/pukEntry" /> + + + <com.android.keyguard.NumPadKey + android:id="@+id/key6" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key7" + androidprv:digit="6" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key7" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key8" + androidprv:digit="7" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key8" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key9" + androidprv:digit="8" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key9" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/delete_button" + androidprv:digit="9" + androidprv:textView="@+id/pukEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key0" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key_enter" + androidprv:digit="0" + androidprv:textView="@+id/pukEntry" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</com.android.keyguard.KeyguardSimPukView> diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt index 7151c429acf9..7031b2be8028 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt @@ -80,8 +80,9 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { `when`(telephonyManager.createForSubscriptionId(anyInt())).thenReturn(telephonyManager) `when`(telephonyManager.supplyIccLockPin(anyString())).thenReturn(mock()) simPinView = - LayoutInflater.from(context).inflate(R.layout.keyguard_sim_pin_view, null) - as KeyguardSimPinView + LayoutInflater.from(context) + .inflate(R.layout.keyguard_sim_pin_view, null) + .requireViewById(R.id.keyguard_sim_pin_view) as KeyguardSimPinView val fakeFeatureFlags = FakeFeatureFlags() val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository()) diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 3780fbd61e79..bbdac5636fa4 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -99,6 +99,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; @@ -126,6 +127,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.LongSparseArray; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -253,6 +255,8 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String MIGRATED_KEYSTORE_NS = "migrated_keystore_namespace"; private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce"; private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys"; + private static final String MIGRATED_WEAVER_DISABLED_ON_UNSECURED_USERS = + "migrated_weaver_disabled_on_unsecured_users"; // Duration that LockSettingsService will store the gatekeeper password for. This allows // multiple biometric enrollments without prompting the user to enter their password via @@ -309,6 +313,10 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mUserCreationAndRemovalLock") private boolean mThirdPartyAppsStarted; + // This list contains the (protectorId, userId) of any protectors that were by replaced by a + // migration and should be destroyed once rollback to the old build is no longer possible. + private ArrayList<Pair<Long, Integer>> mProtectorsToDestroyOnBootCompleted = new ArrayList<>(); + // Current password metrics for all secured users on the device. Updated when user unlocks the // device or changes password. Removed if user is stopped with its CE key evicted. @GuardedBy("this") @@ -363,6 +371,10 @@ public class LockSettingsService extends ILockSettings.Stub { mLockSettingsService.migrateOldDataAfterSystemReady(); mLockSettingsService.deleteRepairModePersistentDataIfNeeded(); } else if (phase == PHASE_BOOT_COMPLETED) { + // In the case of an upgrade, PHASE_BOOT_COMPLETED means that a rollback to the old + // build can no longer occur. This is the time to destroy any migrated protectors. + mLockSettingsService.destroyMigratedProtectors(); + mLockSettingsService.loadEscrowData(); } } @@ -1076,6 +1088,11 @@ public class LockSettingsService extends ILockSettings.Stub { mStorage.deleteRepairModePersistentData(); } + private boolean isWeaverDisabledOnUnsecuredUsers() { + return mContext.getResources().getBoolean( + com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers); + } + // This is called when Weaver is guaranteed to be available (if the device supports Weaver). // It does any synthetic password related work that was delayed from earlier in the boot. private void onThirdPartyAppsStarted() { @@ -1114,13 +1131,20 @@ public class LockSettingsService extends ILockSettings.Stub { // // - Upgrading from Android 14, where unsecured users didn't have Keystore super keys. // + // - Upgrading from a build with config_disableWeaverOnUnsecuredUsers=false to one with + // config_disableWeaverOnUnsecuredUsers=true. (We don't bother to proactively add + // Weaver for the reverse update to false, as it's too late to help in that case.) + // // The end result is that all users, regardless of whether they are secured or not, have - // a synthetic password with all keys initialized and protected by it. + // a synthetic password with all keys initialized and protected by it, and honoring + // config_disableWeaverOnUnsecuredUsers=true when applicable. // // Note: if this migration gets interrupted (e.g. by the device powering off), there // shouldn't be a problem since this will run again on the next boot, and // setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent. - if (!getBoolean(MIGRATED_SP_FULL, false, 0)) { + if (!getBoolean(MIGRATED_SP_FULL, false, 0) + || (isWeaverDisabledOnUnsecuredUsers() + && !getBoolean(MIGRATED_WEAVER_DISABLED_ON_UNSECURED_USERS, false, 0))) { for (UserInfo user : mUserManager.getAliveUsers()) { removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); synchronized (mSpManager) { @@ -1128,6 +1152,9 @@ public class LockSettingsService extends ILockSettings.Stub { } } setBoolean(MIGRATED_SP_FULL, true, 0); + if (isWeaverDisabledOnUnsecuredUsers()) { + setBoolean(MIGRATED_WEAVER_DISABLED_ON_UNSECURED_USERS, true, 0); + } } mThirdPartyAppsStarted = true; @@ -1151,13 +1178,61 @@ public class LockSettingsService extends ILockSettings.Stub { getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId, null); SyntheticPassword sp = result.syntheticPassword; - if (sp == null) { + if (isWeaverDisabledOnUnsecuredUsers()) { + Slog.i(TAG, "config_disableWeaverOnUnsecuredUsers=true"); + + // If config_disableWeaverOnUnsecuredUsers=true, then the Weaver HAL may be buggy and + // need multiple retries before it works here to unwrap the SP, if the SP was already + // protected by Weaver. Note that the problematic HAL can also deadlock if called with + // the ActivityManagerService lock held, but that should not be a problem here since + // that lock isn't held here, unlike unlockUserKeyIfUnsecured() where it is. + for (int i = 0; i < 12 && sp == null; i++) { + Slog.e(TAG, "Failed to unwrap synthetic password. Waiting 5 seconds to retry."); + SystemClock.sleep(5000); + result = mSpManager.unlockLskfBasedProtector(getGateKeeperService(), protectorId, + LockscreenCredential.createNone(), userId, null); + sp = result.syntheticPassword; + } + if (sp == null) { + throw new IllegalStateException( + "Failed to unwrap synthetic password for unsecured user"); + } + // If the SP is protected by Weaver, then remove the Weaver protection in order to make + // config_disableWeaverOnUnsecuredUsers=true take effect. + if (result.usedWeaver) { + Slog.i(TAG, "Removing Weaver protection from the synthetic password"); + // Create a new protector, which will not use Weaver. + long newProtectorId = mSpManager.createLskfBasedProtector( + getGateKeeperService(), LockscreenCredential.createNone(), sp, userId); + + // Out of paranoia, make sure the new protector really works. + result = mSpManager.unlockLskfBasedProtector(getGateKeeperService(), + newProtectorId, LockscreenCredential.createNone(), userId, null); + sp = result.syntheticPassword; + if (sp == null) { + throw new IllegalStateException("New SP protector does not work"); + } + + // Replace the protector. Wait until PHASE_BOOT_COMPLETED to destroy the old + // protector, since the Weaver slot erasure and freeing cannot be rolled back. + setCurrentLskfBasedProtectorId(newProtectorId, userId); + mProtectorsToDestroyOnBootCompleted.add(new Pair(protectorId, userId)); + } else { + Slog.i(TAG, "Synthetic password is already not protected by Weaver"); + } + } else if (sp == null) { Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId); return; } - // While setCeStorageProtection() is idempotent, it does log some error messages when called - // again. Skip it if we know it was already handled by an earlier upgrade to Android 14. - if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { + + // Call setCeStorageProtection(), to re-encrypt the CE key with the SP if it's currently + // encrypted by an empty secret. Skip this if it was definitely already done as part of the + // upgrade to Android 14, since while setCeStorageProtection() is idempotent it does log + // some error messages when called again. Do not skip this if + // config_disableWeaverOnUnsecuredUsers=true, since in that case we'd like to recover from + // the case where an earlier upgrade to Android 14 incorrectly skipped this step. + if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null + || isWeaverDisabledOnUnsecuredUsers()) { Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId); setCeStorageProtection(userId, sp); } @@ -1165,6 +1240,17 @@ public class LockSettingsService extends ILockSettings.Stub { initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true); } + private void destroyMigratedProtectors() { + if (!mProtectorsToDestroyOnBootCompleted.isEmpty()) { + synchronized (mSpManager) { + for (Pair<Long, Integer> pair : mProtectorsToDestroyOnBootCompleted) { + mSpManager.destroyLskfBasedProtector(pair.first, pair.second); + } + } + } + mProtectorsToDestroyOnBootCompleted = null; // The list is no longer needed. + } + /** * Returns the lowest password quality that still presents the same UI for entering it. * diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 3a429b041b3c..47788f2e7d2f 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -195,6 +195,8 @@ class SyntheticPasswordManager { // ERROR: password / token fails verification // RETRY: password / token verification is throttled at the moment. @Nullable public VerifyCredentialResponse gkResponse; + // For unlockLskfBasedProtector() this is set to true if the protector uses Weaver. + public boolean usedWeaver; } /** @@ -532,6 +534,11 @@ class SyntheticPasswordManager { Settings.Global.DEVICE_PROVISIONED, 0) != 0; } + private boolean isWeaverDisabledOnUnsecuredUsers() { + return mContext.getResources().getBoolean( + com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers); + } + @VisibleForTesting protected android.hardware.weaver.V1_0.IWeaver getWeaverHidlService() throws RemoteException { try { @@ -1011,7 +1018,13 @@ class SyntheticPasswordManager { Slogf.i(TAG, "Creating LSKF-based protector %016x for user %d", protectorId, userId); - final IWeaver weaver = getWeaverService(); + final IWeaver weaver; + if (credential.isNone() && isWeaverDisabledOnUnsecuredUsers()) { + weaver = null; + Slog.w(TAG, "Not using Weaver for unsecured user (disabled by config)"); + } else { + weaver = getWeaverService(); + } if (weaver != null) { // Weaver is available, so make the protector use it to verify the LSKF. Do this even // if the LSKF is empty, as that gives us support for securely deleting the protector. @@ -1404,6 +1417,7 @@ class SyntheticPasswordManager { int weaverSlot = loadWeaverSlot(protectorId, userId); if (weaverSlot != INVALID_WEAVER_SLOT) { // Protector uses Weaver to verify the LSKF + result.usedWeaver = true; final IWeaver weaver = getWeaverService(); if (weaver == null) { Slog.e(TAG, "Protector uses Weaver, but Weaver is unavailable"); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java index 50f3a88cc3a2..5bcddc41eb87 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java @@ -1,6 +1,10 @@ package com.android.server.locksettings; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; import android.platform.test.annotations.Presubmit; @@ -56,4 +60,44 @@ public class WeaverBasedSyntheticPasswordTests extends SyntheticPasswordTests { mService.initializeSyntheticPassword(userId); // This should allocate a Weaver slot. assertEquals(Sets.newHashSet(0), mPasswordSlotManager.getUsedSlots()); } + + private int getNumUsedWeaverSlots() { + return mPasswordSlotManager.getUsedSlots().size(); + } + + @Test + public void testDisableWeaverOnUnsecuredUsers_false() { + final int userId = PRIMARY_USER_ID; + when(mResources.getBoolean(eq( + com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers))) + .thenReturn(false); + assertEquals(0, getNumUsedWeaverSlots()); + mService.initializeSyntheticPassword(userId); + assertEquals(1, getNumUsedWeaverSlots()); + assertTrue(mService.setLockCredential(newPassword("password"), nonePassword(), userId)); + assertEquals(1, getNumUsedWeaverSlots()); + assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), userId)); + assertEquals(1, getNumUsedWeaverSlots()); + } + + @Test + public void testDisableWeaverOnUnsecuredUsers_true() { + final int userId = PRIMARY_USER_ID; + when(mResources.getBoolean(eq( + com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers))) + .thenReturn(true); + assertEquals(0, getNumUsedWeaverSlots()); + mService.initializeSyntheticPassword(userId); + assertEquals(0, getNumUsedWeaverSlots()); + assertTrue(mService.setLockCredential(newPassword("password"), nonePassword(), userId)); + assertEquals(1, getNumUsedWeaverSlots()); + assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), userId)); + assertEquals(0, getNumUsedWeaverSlots()); + } + + @Test + public void testDisableWeaverOnUnsecuredUsers_defaultsToFalse() { + assertFalse(mResources.getBoolean( + com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers)); + } } diff --git a/tests/Internal/src/com/android/internal/os/OWNERS b/tests/Internal/src/com/android/internal/os/OWNERS new file mode 100644 index 000000000000..64ffa463bac1 --- /dev/null +++ b/tests/Internal/src/com/android/internal/os/OWNERS @@ -0,0 +1,2 @@ +# ApplicationSharedMemory +per-file *ApplicationSharedMemory* = file:/PERFORMANCE_OWNERS |