summaryrefslogtreecommitdiff
path: root/service/java/com/android/server/deviceconfig/SimPinReplayManager.java
blob: 93c3f5f3a90cb57713466a8b5a68d37fc528b19d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.android.server.deviceconfig;

import android.content.Context;
import android.content.res.Resources;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.google.common.collect.ImmutableList;

/**
 * If device contains a SIM PIN, must prepare <a
 * href="https://source.android.com/docs/core/ota/resume-on-reboot#sim-pin-replay">Sim Pin
 * Replay</a> to unlock the device post reboot.
 *
 * @hide
 */
public class SimPinReplayManager {

  private static final String TAG = "UnattendedRebootManager";

  // The identifier of the system resource value that determines whether auto-sim-unlock feature is
  // enabled/disabled for the device.
  private static final String SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY =
      "config_allow_pin_storage_for_unattended_reboot";
  // This is a copy of the hidden field
  // CarrierConfigManager#KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL. Phonesky uses this key to
  // read the boolean value in carrier configs specifying whether to enable/disable auto-sim-unlock.
  private static final String CARRIER_ENABLE_SIM_PIN_STORAGE_KEY =
      "store_sim_pin_for_unattended_reboot_bool";

  private Context mContext;

  SimPinReplayManager(Context context) {
    mContext = context;
  }

  /** Returns true, if no SIM PIN present or prepared SIM PIN Replay. */
  public boolean prepareSimPinReplay() {
    // Is SIM Pin present?
    ImmutableList<Integer> pinLockedSubscriptionIds = getPinLockedSubscriptionIds(mContext);
    if (pinLockedSubscriptionIds.isEmpty()) {
      return true;
    }

    if (!isSimPinStorageEnabled(mContext, pinLockedSubscriptionIds)) {
      Log.w(TAG, "SIM PIN storage is disabled");
      return false;
    }

    TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
    if (telephonyManager == null) {
      Log.e(TAG, "Failed to prepare SIM PIN Replay, TelephonyManager is null");
      return false;
    }

    int prepareUnattendedRebootResult = telephonyManager.prepareForUnattendedReboot();
    if (prepareUnattendedRebootResult == TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS) {
      Log.i(TAG, "SIM PIN replay prepared");
      return true;
    }
    Log.w(TAG, "Failed to prepare SIM PIN Replay, " + prepareUnattendedRebootResult);
    return false;
  }

  /** Returns a list of telephony subscription IDs (SIM IDs) locked by PIN. */
  private static ImmutableList<Integer> getPinLockedSubscriptionIds(Context context) {
    SubscriptionManager subscriptionManager = context.getSystemService(SubscriptionManager.class);
    int[] subscriptionIds = subscriptionManager.getActiveSubscriptionIdList();
    if (subscriptionIds.length == 0) {
      return ImmutableList.of();
    }

    TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
    ImmutableList.Builder<Integer> pinLockedSubscriptionIdsBuilder = ImmutableList.builder();
    for (int subscriptionId : subscriptionIds) {
      if (telephonyManager.createForSubscriptionId(subscriptionId).isIccLockEnabled()) {
        pinLockedSubscriptionIdsBuilder.add(subscriptionId);
      }
    }
    return pinLockedSubscriptionIdsBuilder.build();
  }

  /**
   * Returns true, if SIM PIN storage is enabled.
   *
   * <p>The SIM PIN storage might be disabled by OEM or by carrier, subscription (SIM) Id is
   * required when checking if the corresponding SIM PIN storage is disabled by the carrier.
   *
   * <p>Both the OEM and carrier enable SIM PIN storage by default. If fails to read the OEM/carrier
   * configs, it assume SIM PIN storage is enabled.
   */
  private static boolean isSimPinStorageEnabled(
      Context context, ImmutableList<Integer> pinLockedSubscriptionIds) {
    if (!isSystemEnableSimPin()) {
      return false;
    }

    // If the carrier enables SIM PIN.
    CarrierConfigManager carrierConfigManager =
        context.getSystemService(CarrierConfigManager.class);
    if (carrierConfigManager == null) {
      Log.w(TAG, "CarrierConfigManager is null");
      return true;
    }
    for (int pinLockedSubscriptionId : pinLockedSubscriptionIds) {
      PersistableBundle subscriptionConfig =
          carrierConfigManager.getConfigForSubId(
              pinLockedSubscriptionId, CARRIER_ENABLE_SIM_PIN_STORAGE_KEY);
      // Only disable if carrier explicitly disables sim pin storage.
      if (!subscriptionConfig.isEmpty()
          && !subscriptionConfig.getBoolean(
              CARRIER_ENABLE_SIM_PIN_STORAGE_KEY, /* defaultValue= */ true)) {
        Log.w(
            TAG,
            "The carrier disables SIM PIN storage on subscription ID " + pinLockedSubscriptionId);
        return false;
      }
    }
    Log.v(TAG, "SIM PIN Storage is enabled");
    return true;
  }

  private static boolean isSystemEnableSimPin() {
    try {
      boolean value =
          Resources.getSystem()
              .getBoolean(
                  Resources.getSystem()
                      .getIdentifier(
                          SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY,
                          /* defType= */ "bool",
                          /* defPackage= */ "android"));
      Log.i(TAG, SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY + " = " + value);
      return value;
    } catch (Resources.NotFoundException e) {
      Log.e(TAG, "Could not read system resource value ," + SYSTEM_ENABLE_SIM_PIN_STORAGE_KEY);
      // When not explicitly disabled, assume SIM PIN storage functions properly.
      return true;
    }
  }
}