blob: baaa68480abcb432658a07d5cc999f0bf9382b14 [file] [log] [blame]
Gil Cukierman6dac5eb2022-09-19 16:09:04 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.os.UserManager;
24import android.telephony.RadioAccessFamily;
25import android.telephony.SubscriptionInfo;
26import android.telephony.SubscriptionManager;
27import android.telephony.TelephonyManager;
28import android.util.Log;
29
30import com.android.internal.annotations.VisibleForTesting;
31import com.android.internal.telephony.RILConstants;
32
Gil Cukiermand6cae882022-12-29 12:02:31 -050033import java.util.ArrayList;
34import java.util.Collection;
35import java.util.HashSet;
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000036import java.util.List;
Gil Cukiermand6cae882022-12-29 12:02:31 -050037import java.util.Set;
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000038import java.util.concurrent.Executor;
Gil Cukiermand6cae882022-12-29 12:02:31 -050039import java.util.concurrent.Executors;
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000040
41/**
42 * A {@link BroadcastReceiver} that ensures that user restrictions are correctly applied to
43 * telephony.
44 * This includes handling broadcasts from user restriction state changes, as well as ensuring that
45 * SIM-specific settings are correctly applied when new subscriptions become active.
46 *
Gil Cukiermand6cae882022-12-29 12:02:31 -050047 * <p>
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000048 * Callers are expected to call {@code init()} and keep an instance of this class alive.
Gil Cukiermand6cae882022-12-29 12:02:31 -050049 * </p>
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000050 */
51public class Telephony2gUpdater extends BroadcastReceiver {
Gil Cukiermand6cae882022-12-29 12:02:31 -050052 private static final String TAG = "Telephony2gUpdater";
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000053
54 // We can't interact with the HAL on the main thread of the phone process (where
55 // receivers are run by default), so we execute our logic from a separate thread.
Gil Cukiermand6cae882022-12-29 12:02:31 -050056 // The correctness of this implementation relies heavily on this executor ensuring
57 // tasks are serially executed i.e. ExecutorService.newSingleThreadExecutor()
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000058 private final Executor mExecutor;
59 private final Context mContext;
60 private final long mBaseAllowedNetworks;
61
Gil Cukiermand6cae882022-12-29 12:02:31 -050062 private UserManager mUserManager;
63 private TelephonyManager mTelephonyManager;
64 private SubscriptionManager mSubscriptionManager;
65
66 // The current subscription ids
67 // Ensure this value is never accessed concurrently
68 private Set<Integer> mCurrentSubscriptions;
69 // We keep track of the last value to avoid updating when unrelated user restrictions change
70 // Ensure this value is never accessed concurrently
71 private boolean mDisallowCellular2gRestriction;
72
73 public Telephony2gUpdater(Context context) {
74 this(Executors.newSingleThreadExecutor(), context,
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000075 RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE));
76 }
77
Gil Cukiermand6cae882022-12-29 12:02:31 -050078 @VisibleForTesting
79 public Telephony2gUpdater(Executor executor, Context context, long baseAllowedNetworks) {
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000080 mExecutor = executor;
81 mContext = context;
82 mBaseAllowedNetworks = baseAllowedNetworks;
Gil Cukiermand6cae882022-12-29 12:02:31 -050083
84 mUserManager = mContext.getSystemService(UserManager.class);
85 mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
86 mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
87
88 // All user restrictions are false by default
89 mDisallowCellular2gRestriction = false;
90 mCurrentSubscriptions = new HashSet<>();
Gil Cukierman6dac5eb2022-09-19 16:09:04 +000091 }
92
93 /**
94 * Register the given instance as a {@link BroadcastReceiver} and a {@link
95 * SubscriptionManager.OnSubscriptionsChangedListener}.
96 */
97 public void init() {
98 mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
99 mExecutor, new SubscriptionListener());
100 IntentFilter filter = new IntentFilter();
101 filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
102 mContext.registerReceiver(this, filter);
103 }
104
105 @Override
106 public void onReceive(Context context, Intent intent) {
107 if (context == null || intent == null) return;
108 Log.i(TAG, "Received callback for action " + intent.getAction());
109 final PendingResult result = goAsync();
110 mExecutor.execute(() -> {
Gil Cukiermand6cae882022-12-29 12:02:31 -0500111 boolean disallow2g = mUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
112 if (mDisallowCellular2gRestriction == disallow2g) {
113 Log.i(TAG, "No update to DISALLOW_CELLULAR_2G restriction.");
114 return;
115 }
116
117 mDisallowCellular2gRestriction = disallow2g;
118
119 Log.i(TAG, "Running handler for all subscriptions based on DISALLOW_CELLULAR_2G change."
120 + " Restriction value: " + mDisallowCellular2gRestriction);
121 handleUserRestrictionsChanged(mCurrentSubscriptions);
122 if (result != null) {
123 result.finish();
124 }
Gil Cukierman6dac5eb2022-09-19 16:09:04 +0000125 });
126 }
127
128 /**
Gil Cukiermand6cae882022-12-29 12:02:31 -0500129 * Update subscriptions with allowed network types depending on the current state
130 * of the {@link UserManager#DISALLOW_CELLULAR_2G}.
131 *
132 * @param subIds A list of subIds to update.
Gil Cukierman6dac5eb2022-09-19 16:09:04 +0000133 */
Gil Cukiermand6cae882022-12-29 12:02:31 -0500134 private void handleUserRestrictionsChanged(Collection<Integer> subIds) {
Gil Cukierman6dac5eb2022-09-19 16:09:04 +0000135 final long twoGBitmask = TelephonyManager.NETWORK_CLASS_BITMASK_2G;
136
Gil Cukierman6dac5eb2022-09-19 16:09:04 +0000137 long allowedNetworkTypes = mBaseAllowedNetworks;
138
139 // 2G device admin controls are global
Gil Cukiermand6cae882022-12-29 12:02:31 -0500140 for (Integer subId : subIds) {
141 TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subId);
142 if (mDisallowCellular2gRestriction) {
143 Log.i(TAG, "Disabling 2g based on user restriction for subId: " + subId);
Gil Cukierman6dac5eb2022-09-19 16:09:04 +0000144 allowedNetworkTypes &= ~twoGBitmask;
145 } else {
Gil Cukiermand6cae882022-12-29 12:02:31 -0500146 Log.i(TAG, "Enabling 2g based on user restriction for subId: " + subId);
Gil Cukierman6dac5eb2022-09-19 16:09:04 +0000147 allowedNetworkTypes |= twoGBitmask;
148 }
149 telephonyManager.setAllowedNetworkTypesForReason(
150 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS,
151 allowedNetworkTypes);
152 }
153 }
154
155 private class SubscriptionListener extends SubscriptionManager.OnSubscriptionsChangedListener {
156 @Override
157 public void onSubscriptionsChanged() {
Gil Cukiermand6cae882022-12-29 12:02:31 -0500158 // Note that this entire callback gets invoked in the single threaded executor
159 List<SubscriptionInfo> allSubscriptions =
160 mSubscriptionManager.getCompleteActiveSubscriptionInfoList();
161
162 HashSet<Integer> updatedSubIds = new HashSet<>(allSubscriptions.size());
163 List<Integer> newSubIds = new ArrayList<>();
164
165 for (SubscriptionInfo info : allSubscriptions) {
166 updatedSubIds.add(info.getSubscriptionId());
167 if (!mCurrentSubscriptions.contains(info.getSubscriptionId())) {
168 newSubIds.add(info.getSubscriptionId());
169 }
170 }
171
172 mCurrentSubscriptions = updatedSubIds;
173
174 if (newSubIds.isEmpty()) {
175 Log.d(TAG, "No new subIds. Skipping update.");
176 return;
177 }
178
179 Log.i(TAG, "New subscriptions found. Running handler to update 2g restrictions with "
180 + "subIds " + newSubIds.toString());
181 handleUserRestrictionsChanged(newSubIds);
Gil Cukierman6dac5eb2022-09-19 16:09:04 +0000182 }
183 }
184
185}