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.net.NetworkTemplate.NETWORK_TYPE_5G_NSA;
20 import static android.net.NetworkTemplate.getCollapsedRatType;
21 
22 import android.annotation.NonNull;
23 import android.content.Context;
24 import android.telephony.Annotation;
25 import android.telephony.NetworkRegistrationInfo;
26 import android.telephony.PhoneStateListener;
27 import android.telephony.ServiceState;
28 import android.telephony.SubscriptionManager;
29 import android.telephony.TelephonyManager;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.util.CollectionUtils;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.concurrent.CopyOnWriteArrayList;
39 import java.util.concurrent.Executor;
40 
41 /**
42  * Helper class that watches for events that are triggered per subscription.
43  */
44 public class NetworkStatsSubscriptionsMonitor extends
45         SubscriptionManager.OnSubscriptionsChangedListener {
46 
47     /**
48      * Interface that this monitor uses to delegate event handling to NetworkStatsService.
49      */
50     public interface Delegate {
51         /**
52          * Notify that the collapsed RAT type has been changed for any subscription. The method
53          * will also be triggered for any existing sub when start and stop monitoring.
54          *
55          * @param subscriberId IMSI of the subscription.
56          * @param collapsedRatType collapsed RAT type.
57          *                         @see android.net.NetworkTemplate#getCollapsedRatType(int).
58          */
onCollapsedRatTypeChanged(@onNull String subscriberId, @Annotation.NetworkType int collapsedRatType)59         void onCollapsedRatTypeChanged(@NonNull String subscriberId,
60                 @Annotation.NetworkType int collapsedRatType);
61     }
62     private final Delegate mDelegate;
63 
64     /**
65      * Receivers that watches for {@link ServiceState} changes for each subscription, to
66      * monitor the transitioning between Radio Access Technology(RAT) types for each sub.
67      */
68     @NonNull
69     private final CopyOnWriteArrayList<RatTypeListener> mRatListeners =
70             new CopyOnWriteArrayList<>();
71 
72     @NonNull
73     private final SubscriptionManager mSubscriptionManager;
74     @NonNull
75     private final TelephonyManager mTeleManager;
76 
77     @NonNull
78     private final Executor mExecutor;
79 
NetworkStatsSubscriptionsMonitor(@onNull Context context, @NonNull Executor executor, @NonNull Delegate delegate)80     NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor,
81             @NonNull Delegate delegate) {
82         super();
83         mSubscriptionManager = (SubscriptionManager) context.getSystemService(
84                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
85         mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
86         mExecutor = executor;
87         mDelegate = delegate;
88     }
89 
90     @Override
onSubscriptionsChanged()91     public void onSubscriptionsChanged() {
92         // Collect active subId list, hidden subId such as opportunistic subscriptions are
93         // also needed to track CBRS.
94         final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager);
95 
96         for (final int subId : newSubs) {
97             final RatTypeListener match = CollectionUtils.find(mRatListeners,
98                     it -> it.mSubId == subId);
99             if (match != null) continue;
100 
101             // Create listener for every newly added sub. Also store subscriberId into it to
102             // prevent binder call to telephony when querying RAT.
103             final String subscriberId = mTeleManager.getSubscriberId(subId);
104             if (TextUtils.isEmpty(subscriberId)) {
105                 Log.wtf(NetworkStatsService.TAG,
106                         "Empty subscriberId for newly added sub: " + subId);
107             }
108             final RatTypeListener listener =
109                     new RatTypeListener(mExecutor, this, subId, subscriberId);
110             mRatListeners.add(listener);
111 
112             // Register listener to the telephony manager that associated with specific sub.
113             mTeleManager.createForSubscriptionId(subId)
114                     .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
115         }
116 
117         for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
118             // If the new list contains the subId of the listener, keeps it.
119             final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId);
120             if (match != null) continue;
121 
122             handleRemoveRatTypeListener(listener);
123         }
124     }
125 
126     @NonNull
getActiveSubIdList(@onNull SubscriptionManager subscriptionManager)127     private List<Integer> getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) {
128         final ArrayList<Integer> ret = new ArrayList<>();
129         final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList();
130         for (int id : ids) ret.add(id);
131         return ret;
132     }
133 
134     /**
135      * Get a collapsed RatType for the given subscriberId.
136      *
137      * @param subscriberId the target subscriberId
138      * @return collapsed RatType for the given subscriberId
139      */
getRatTypeForSubscriberId(@onNull String subscriberId)140     public int getRatTypeForSubscriberId(@NonNull String subscriberId) {
141         final RatTypeListener match = CollectionUtils.find(mRatListeners,
142                 it -> TextUtils.equals(subscriberId, it.mSubscriberId));
143         return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN;
144     }
145 
146     /**
147      * Start monitoring events that triggered per subscription.
148      */
start()149     public void start() {
150         mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this);
151     }
152 
153     /**
154      * Unregister subscription changes and all listeners for each subscription.
155      */
stop()156     public void stop() {
157         mSubscriptionManager.removeOnSubscriptionsChangedListener(this);
158 
159         for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
160             handleRemoveRatTypeListener(listener);
161         }
162     }
163 
handleRemoveRatTypeListener(@onNull RatTypeListener listener)164     private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) {
165         mTeleManager.createForSubscriptionId(listener.mSubId)
166                 .listen(listener, PhoneStateListener.LISTEN_NONE);
167         mRatListeners.remove(listener);
168 
169         // Removal of subscriptions doesn't generate RAT changed event, fire it for every
170         // RatTypeListener.
171         mDelegate.onCollapsedRatTypeChanged(
172                 listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN);
173     }
174 
175     static class RatTypeListener extends PhoneStateListener {
176         // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}.
177         @NonNull
178         private final int mSubId;
179 
180         // IMSI to identifying the corresponding network from {@link NetworkState}.
181         // See {@link TelephonyManager#getSubscriberId}.
182         @NonNull
183         private final String mSubscriberId;
184 
185         private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
186         @NonNull
187         private final NetworkStatsSubscriptionsMonitor mMonitor;
188 
RatTypeListener(@onNull Executor executor, @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, @NonNull String subscriberId)189         RatTypeListener(@NonNull Executor executor,
190                 @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId,
191                 @NonNull String subscriberId) {
192             super(executor);
193             mSubId = subId;
194             mSubscriberId = subscriberId;
195             mMonitor = monitor;
196         }
197 
198         @Override
onServiceStateChanged(@onNull ServiceState ss)199         public void onServiceStateChanged(@NonNull ServiceState ss) {
200             // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony
201             // would report RAT = 5G_NR.
202             // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and
203             // network allocates a secondary 5G cell so telephony reports RAT = LTE along with
204             // NR state as connected. In such case, attributes the data usage to NR.
205             // See b/160727498.
206             final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE
207                     || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA)
208                     && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED;
209 
210             final int networkType =
211                     (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType());
212             final int collapsedRatType = getCollapsedRatType(networkType);
213             if (collapsedRatType == mLastCollapsedRatType) return;
214 
215             if (NetworkStatsService.LOGD) {
216                 Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): "
217                         + mLastCollapsedRatType + " -> " + collapsedRatType);
218             }
219             mLastCollapsedRatType = collapsedRatType;
220             mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType);
221         }
222 
223         @VisibleForTesting
getSubId()224         public int getSubId() {
225             return mSubId;
226         }
227     }
228 }
229