diff options
| author | 2020-04-08 10:18:02 +0000 | |
|---|---|---|
| committer | 2020-04-08 10:18:02 +0000 | |
| commit | cc0c65dbb5c193f76ec8bb9a041ebeb8c77c702b (patch) | |
| tree | ee36b1ae9f4b3196ae793ea78abe23a3cb43e7e2 | |
| parent | f5715044578182e43d55f19886ade9c0b0ad240d (diff) | |
| parent | aca29a3e87b2b2b6c2c9e914073b60a5b69b3fed (diff) | |
Merge "[SM09] Add helper class to monitor RAT type change per sub" into rvc-dev
| -rw-r--r-- | services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java new file mode 100644 index 000000000000..0bdf3f22ee9a --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.net.NetworkTemplate.getCollapsedRatType; + +import android.annotation.NonNull; +import android.content.Context; +import android.telephony.Annotation; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; + +/** + * Helper class that watches for events that are triggered per subscription. + */ +// TODO (b/152176562): Write tests to verify subscription changes generate corresponding +// register/unregister calls. +public class NetworkStatsSubscriptionsMonitor extends + SubscriptionManager.OnSubscriptionsChangedListener { + + /** + * Interface that this monitor uses to delegate event handling to NetworkStatsService. + */ + public interface Delegate { + /** + * Notify that the collapsed RAT type has been changed for any subscription. The method + * will also be triggered for any existing sub when start and stop monitoring. + * + * @param subscriberId IMSI of the subscription. + * @param collapsedRatType collapsed RAT type. + * @see android.net.NetworkTemplate#getCollapsedRatType(int). + */ + void onCollapsedRatTypeChanged(@NonNull String subscriberId, + @Annotation.NetworkType int collapsedRatType); + } + private final Delegate mDelegate; + + /** + * Receivers that watches for {@link ServiceState} changes for each subscription, to + * monitor the transitioning between Radio Access Technology(RAT) types for each sub. + */ + @NonNull + private final CopyOnWriteArrayList<RatTypeListener> mRatListeners = + new CopyOnWriteArrayList<>(); + + @NonNull + private final SubscriptionManager mSubscriptionManager; + @NonNull + private final TelephonyManager mTeleManager; + + @NonNull + private final Executor mExecutor; + + NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor, + @NonNull Delegate delegate) { + super(); + mSubscriptionManager = (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + mExecutor = executor; + mDelegate = delegate; + } + + @Override + public void onSubscriptionsChanged() { + // Collect active subId list, hidden subId such as opportunistic subscriptions are + // also needed to track CBRS. + final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager); + + for (final int subId : newSubs) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> it.mSubId == subId); + if (match != null) continue; + + // Create listener for every newly added sub. Also store subscriberId into it to + // prevent binder call to telephony when querying RAT. + final String subscriberId = mTeleManager.getSubscriberId(subId); + if (TextUtils.isEmpty(subscriberId)) { + Log.wtf(NetworkStatsService.TAG, + "Empty subscriberId for newly added sub: " + subId); + } + final RatTypeListener listener = + new RatTypeListener(mExecutor, this, subId, subscriberId); + mRatListeners.add(listener); + + // Register listener to the telephony manager that associated with specific sub. + mTeleManager.createForSubscriptionId(subId) + .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + } + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + // If the new list contains the subId of the listener, keeps it. + final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); + if (match != null) continue; + + handleRemoveRatTypeListener(listener); + } + } + + @NonNull + private List<Integer> getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { + final ArrayList<Integer> ret = new ArrayList<>(); + final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); + for (int id : ids) ret.add(id); + return ret; + } + + /** + * Get a collapsed RatType for the given subscriberId. + * + * @param subscriberId the target subscriberId + * @return collapsed RatType for the given subscriberId + */ + public int getRatTypeForSubscriberId(@NonNull String subscriberId) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> TextUtils.equals(subscriberId, it.mSubscriberId)); + return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + + /** + * Start monitoring events that triggered per subscription. + */ + public void start() { + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); + } + + /** + * Unregister subscription changes and all listeners for each subscription. + */ + public void stop() { + mSubscriptionManager.removeOnSubscriptionsChangedListener(this); + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + handleRemoveRatTypeListener(listener); + } + } + + private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { + mTeleManager.createForSubscriptionId(listener.mSubId) + .listen(listener, PhoneStateListener.LISTEN_NONE); + mRatListeners.remove(listener); + + // Removal of subscriptions doesn't generate RAT changed event, fire it for every + // RatTypeListener. + mDelegate.onCollapsedRatTypeChanged( + listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); + } + + static class RatTypeListener extends PhoneStateListener { + // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. + @NonNull + private final int mSubId; + + // IMSI to identifying the corresponding network from {@link NetworkState}. + // See {@link TelephonyManager#getSubscriberId}. + @NonNull + private final String mSubscriberId; + + private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + @NonNull + private final NetworkStatsSubscriptionsMonitor mMonitor; + + RatTypeListener(@NonNull Executor executor, + @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, + @NonNull String subscriberId) { + super(executor); + mSubId = subId; + mSubscriberId = subscriberId; + mMonitor = monitor; + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (NetworkStatsService.LOGD) { + Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + mLastCollapsedRatType = collapsedRatType; + mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); + } + } +} |