1 /* 2 * Copyright (C) 2020 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 17 package com.android.server.net; 18 19 import static android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA; 20 import static android.app.usage.NetworkStatsManager.getCollapsedRatType; 21 import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED; 22 import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA; 23 import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; 24 25 import android.annotation.NonNull; 26 import android.annotation.TargetApi; 27 import android.content.Context; 28 import android.os.Build; 29 import android.telephony.SubscriptionManager; 30 import android.telephony.TelephonyCallback; 31 import android.telephony.TelephonyDisplayInfo; 32 import android.telephony.TelephonyManager; 33 import android.text.TextUtils; 34 import android.util.Log; 35 import android.util.Pair; 36 37 import com.android.internal.annotations.VisibleForTesting; 38 import com.android.net.module.util.CollectionUtils; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.concurrent.CopyOnWriteArrayList; 43 import java.util.concurrent.Executor; 44 45 /** 46 * Helper class that watches for events that are triggered per subscription. 47 */ 48 @TargetApi(Build.VERSION_CODES.TIRAMISU) 49 public class NetworkStatsSubscriptionsMonitor extends 50 SubscriptionManager.OnSubscriptionsChangedListener { 51 52 /** 53 * Interface that this monitor uses to delegate event handling to NetworkStatsService. 54 */ 55 public interface Delegate { 56 /** 57 * Notify that the collapsed RAT type has been changed for any subscription. The method 58 * will also be triggered for any existing sub when start and stop monitoring. 59 * 60 * @param subscriberId IMSI of the subscription. 61 * @param collapsedRatType collapsed RAT type. 62 * @see android.app.usage.NetworkStatsManager#getCollapsedRatType(int). 63 */ onCollapsedRatTypeChanged(@onNull String subscriberId, int collapsedRatType)64 void onCollapsedRatTypeChanged(@NonNull String subscriberId, int collapsedRatType); 65 } 66 private final Delegate mDelegate; 67 68 /** 69 * Receivers that watches for {@link TelephonyDisplayInfo} changes for each subscription, to 70 * monitor the transitioning between Radio Access Technology(RAT) types for each sub. 71 */ 72 @NonNull 73 private final CopyOnWriteArrayList<RatTypeListener> mRatListeners = 74 new CopyOnWriteArrayList<>(); 75 76 @NonNull 77 private final SubscriptionManager mSubscriptionManager; 78 @NonNull 79 private final TelephonyManager mTeleManager; 80 81 @NonNull 82 private final Executor mExecutor; 83 NetworkStatsSubscriptionsMonitor(@onNull Context context, @NonNull Executor executor, @NonNull Delegate delegate)84 NetworkStatsSubscriptionsMonitor(@NonNull Context context, 85 @NonNull Executor executor, @NonNull Delegate delegate) { 86 super(); 87 mSubscriptionManager = (SubscriptionManager) context.getSystemService( 88 Context.TELEPHONY_SUBSCRIPTION_SERVICE); 89 mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 90 mExecutor = executor; 91 mDelegate = delegate; 92 } 93 94 @Override onSubscriptionsChanged()95 public void onSubscriptionsChanged() { 96 // Collect active subId list, hidden subId such as opportunistic subscriptions are 97 // also needed to track CBRS. 98 final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager); 99 100 // IMSI is needed for every newly added sub. Listener stores subscriberId into it to 101 // prevent binder call to telephony when querying RAT. Keep listener registration with empty 102 // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported 103 // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. 104 final List<Pair<Integer, String>> filteredNewSubs = new ArrayList<>(); 105 for (final int subId : newSubs) { 106 final String subscriberId = 107 mTeleManager.createForSubscriptionId(subId).getSubscriberId(); 108 if (!TextUtils.isEmpty(subscriberId)) { 109 filteredNewSubs.add(new Pair(subId, subscriberId)); 110 } 111 } 112 113 for (final Pair<Integer, String> sub : filteredNewSubs) { 114 // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be 115 // suddenly change regardless of subId, such as switch IMSI feature in modem side. 116 // If that happens, register new listener with new IMSI and remove old one later. 117 if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) { 118 continue; 119 } 120 121 final RatTypeListener listener = new RatTypeListener(this, sub.first, sub.second); 122 mRatListeners.add(listener); 123 124 // Register listener to the telephony manager that associated with specific sub. 125 mTeleManager.createForSubscriptionId(sub.first) 126 .registerTelephonyCallback(mExecutor, listener); 127 Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first); 128 } 129 130 for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { 131 // If there is no subId and IMSI matched the listener, removes it. 132 if (!CollectionUtils.any(filteredNewSubs, 133 it -> listener.equalsKey(it.first, it.second))) { 134 handleRemoveRatTypeListener(listener); 135 } 136 } 137 } 138 139 @NonNull getActiveSubIdList(@onNull SubscriptionManager subscriptionManager)140 private List<Integer> getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { 141 final ArrayList<Integer> ret = new ArrayList<>(); 142 final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); 143 for (int id : ids) ret.add(id); 144 return ret; 145 } 146 147 /** 148 * Get a collapsed RatType for the given subscriberId. 149 * 150 * @param subscriberId the target subscriberId 151 * @return collapsed RatType for the given subscriberId 152 */ getRatTypeForSubscriberId(@onNull String subscriberId)153 public int getRatTypeForSubscriberId(@NonNull String subscriberId) { 154 final int index = CollectionUtils.indexOf(mRatListeners, 155 it -> TextUtils.equals(subscriberId, it.mSubscriberId)); 156 return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType 157 : TelephonyManager.NETWORK_TYPE_UNKNOWN; 158 } 159 160 /** 161 * Start monitoring events that triggered per subscription. 162 */ start()163 public void start() { 164 mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); 165 } 166 167 /** 168 * Unregister subscription changes and all listeners for each subscription. 169 */ stop()170 public void stop() { 171 mSubscriptionManager.removeOnSubscriptionsChangedListener(this); 172 173 for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { 174 handleRemoveRatTypeListener(listener); 175 } 176 } 177 handleRemoveRatTypeListener(@onNull RatTypeListener listener)178 private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { 179 mTeleManager.createForSubscriptionId(listener.mSubId) 180 .unregisterTelephonyCallback(listener); 181 Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); 182 mRatListeners.remove(listener); 183 184 // Removal of subscriptions doesn't generate RAT changed event, fire it for every 185 // RatTypeListener. 186 mDelegate.onCollapsedRatTypeChanged( 187 listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); 188 } 189 190 static class RatTypeListener extends TelephonyCallback 191 implements TelephonyCallback.DisplayInfoListener { 192 // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. 193 @NonNull 194 private final int mSubId; 195 196 // IMSI to identifying the corresponding network from {@link NetworkState}. 197 // See {@link TelephonyManager#getSubscriberId}. 198 @NonNull 199 private final String mSubscriberId; 200 201 private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; 202 @NonNull 203 private final NetworkStatsSubscriptionsMonitor mMonitor; 204 RatTypeListener(@onNull NetworkStatsSubscriptionsMonitor monitor, int subId, @NonNull String subscriberId)205 RatTypeListener(@NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, 206 @NonNull String subscriberId) { 207 mSubId = subId; 208 mSubscriberId = subscriberId; 209 mMonitor = monitor; 210 } 211 212 @Override onDisplayInfoChanged(TelephonyDisplayInfo displayInfo)213 public void onDisplayInfoChanged(TelephonyDisplayInfo displayInfo) { 214 // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony 215 // would report RAT = 5G_NR. 216 // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and 217 // network allocates a secondary 5G cell so telephony reports RAT = LTE along with 218 // NR state as connected. In such case, attributes the data usage to NR. 219 // See b/160727498. 220 final boolean is5GNsa = displayInfo.getNetworkType() == NETWORK_TYPE_LTE 221 && (displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_NSA 222 || displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_ADVANCED); 223 224 final int networkType = 225 (is5GNsa ? NETWORK_TYPE_5G_NSA : displayInfo.getNetworkType()); 226 final int collapsedRatType = getCollapsedRatType(networkType); 227 if (collapsedRatType == mLastCollapsedRatType) return; 228 229 if (NetworkStatsService.LOGD) { 230 Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " 231 + mLastCollapsedRatType + " -> " + collapsedRatType); 232 } 233 mLastCollapsedRatType = collapsedRatType; 234 mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); 235 } 236 237 @VisibleForTesting getSubId()238 public int getSubId() { 239 return mSubId; 240 } 241 equalsKey(int subId, @NonNull String subscriberId)242 boolean equalsKey(int subId, @NonNull String subscriberId) { 243 return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId); 244 } 245 } 246 } 247