1 package com.android.server.deviceconfig;
2 
3 import android.content.Context;
4 import android.content.res.Resources;
5 import android.os.PersistableBundle;
6 import android.telephony.CarrierConfigManager;
7 import android.telephony.SubscriptionManager;
8 import android.telephony.TelephonyManager;
9 import android.util.Log;
10 
11 import com.google.common.collect.ImmutableList;
12 
13 /**
14  * If device contains a SIM PIN, must prepare <a
15  * href="https://source.android.com/docs/core/ota/resume-on-reboot#sim-pin-replay">Sim Pin
16  * Replay</a> to unlock the device post reboot.
17  *
18  * @hide
19  */
20 public class SimPinReplayManager {
21 
22   private static final String TAG = "UnattendedRebootManager";
23 
24   // The identifier of the system resource value that determines whether auto-sim-unlock feature is
25   // enabled/disabled for the device.
26   private static final String SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY =
27       "config_allow_pin_storage_for_unattended_reboot";
28   // This is a copy of the hidden field
29   // CarrierConfigManager#KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL. Phonesky uses this key to
30   // read the boolean value in carrier configs specifying whether to enable/disable auto-sim-unlock.
31   private static final String CARRIER_ENABLE_SIM_PIN_STORAGE_KEY =
32       "store_sim_pin_for_unattended_reboot_bool";
33 
34   private Context mContext;
35 
SimPinReplayManager(Context context)36   SimPinReplayManager(Context context) {
37     mContext = context;
38   }
39 
40   /** Returns true, if no SIM PIN present or prepared SIM PIN Replay. */
prepareSimPinReplay()41   public boolean prepareSimPinReplay() {
42     // Is SIM Pin present?
43     ImmutableList<Integer> pinLockedSubscriptionIds = getPinLockedSubscriptionIds(mContext);
44     if (pinLockedSubscriptionIds.isEmpty()) {
45       return true;
46     }
47 
48     if (!isSimPinStorageEnabled(mContext, pinLockedSubscriptionIds)) {
49       Log.w(TAG, "SIM PIN storage is disabled");
50       return false;
51     }
52 
53     TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
54     if (telephonyManager == null) {
55       Log.e(TAG, "Failed to prepare SIM PIN Replay, TelephonyManager is null");
56       return false;
57     }
58 
59     int prepareUnattendedRebootResult = telephonyManager.prepareForUnattendedReboot();
60     if (prepareUnattendedRebootResult == TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS) {
61       Log.i(TAG, "SIM PIN replay prepared");
62       return true;
63     }
64     Log.w(TAG, "Failed to prepare SIM PIN Replay, " + prepareUnattendedRebootResult);
65     return false;
66   }
67 
68   /** Returns a list of telephony subscription IDs (SIM IDs) locked by PIN. */
getPinLockedSubscriptionIds(Context context)69   private static ImmutableList<Integer> getPinLockedSubscriptionIds(Context context) {
70     SubscriptionManager subscriptionManager = context.getSystemService(SubscriptionManager.class);
71     int[] subscriptionIds = subscriptionManager.getActiveSubscriptionIdList();
72     if (subscriptionIds.length == 0) {
73       return ImmutableList.of();
74     }
75 
76     TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
77     ImmutableList.Builder<Integer> pinLockedSubscriptionIdsBuilder = ImmutableList.builder();
78     for (int subscriptionId : subscriptionIds) {
79       if (telephonyManager.createForSubscriptionId(subscriptionId).isIccLockEnabled()) {
80         pinLockedSubscriptionIdsBuilder.add(subscriptionId);
81       }
82     }
83     return pinLockedSubscriptionIdsBuilder.build();
84   }
85 
86   /**
87    * Returns true, if SIM PIN storage is enabled.
88    *
89    * <p>The SIM PIN storage might be disabled by OEM or by carrier, subscription (SIM) Id is
90    * required when checking if the corresponding SIM PIN storage is disabled by the carrier.
91    *
92    * <p>Both the OEM and carrier enable SIM PIN storage by default. If fails to read the OEM/carrier
93    * configs, it assume SIM PIN storage is enabled.
94    */
isSimPinStorageEnabled( Context context, ImmutableList<Integer> pinLockedSubscriptionIds)95   private static boolean isSimPinStorageEnabled(
96       Context context, ImmutableList<Integer> pinLockedSubscriptionIds) {
97     if (!isSystemEnableSimPin()) {
98       return false;
99     }
100 
101     // If the carrier enables SIM PIN.
102     CarrierConfigManager carrierConfigManager =
103         context.getSystemService(CarrierConfigManager.class);
104     if (carrierConfigManager == null) {
105       Log.w(TAG, "CarrierConfigManager is null");
106       return true;
107     }
108     for (int pinLockedSubscriptionId : pinLockedSubscriptionIds) {
109       PersistableBundle subscriptionConfig =
110           carrierConfigManager.getConfigForSubId(
111               pinLockedSubscriptionId, CARRIER_ENABLE_SIM_PIN_STORAGE_KEY);
112       // Only disable if carrier explicitly disables sim pin storage.
113       if (!subscriptionConfig.isEmpty()
114           && !subscriptionConfig.getBoolean(
115               CARRIER_ENABLE_SIM_PIN_STORAGE_KEY, /* defaultValue= */ true)) {
116         Log.w(
117             TAG,
118             "The carrier disables SIM PIN storage on subscription ID " + pinLockedSubscriptionId);
119         return false;
120       }
121     }
122     Log.v(TAG, "SIM PIN Storage is enabled");
123     return true;
124   }
125 
isSystemEnableSimPin()126   private static boolean isSystemEnableSimPin() {
127     try {
128       boolean value =
129           Resources.getSystem()
130               .getBoolean(
131                   Resources.getSystem()
132                       .getIdentifier(
133                           SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY,
134                           /* defType= */ "bool",
135                           /* defPackage= */ "android"));
136       Log.i(TAG, SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY + " = " + value);
137       return value;
138     } catch (Resources.NotFoundException e) {
139       Log.e(TAG, "Could not read system resource value ," + SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY);
140       // When not explicitly disabled, assume SIM PIN storage functions properly.
141       return true;
142     }
143   }
144 }
145