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