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.settings.datausage.lib; 18 19 import android.content.Context; 20 import android.net.NetworkStats; 21 import android.net.NetworkTemplate; 22 import android.telephony.SubscriptionInfo; 23 import android.telephony.SubscriptionManager; 24 import android.telephony.TelephonyManager; 25 import android.util.ArraySet; 26 import android.util.Log; 27 28 import androidx.annotation.NonNull; 29 30 import com.android.internal.util.ArrayUtils; 31 32 import java.util.Arrays; 33 import java.util.List; 34 import java.util.Set; 35 36 /** 37 * Lib class for data usage 38 */ 39 public class DataUsageLib { 40 private static final String TAG = "DataUsageLib"; 41 42 /** 43 * Return mobile NetworkTemplate based on {@code subId} 44 */ getMobileTemplate(Context context, int subId)45 public static NetworkTemplate getMobileTemplate(Context context, int subId) { 46 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 47 final int mobileDefaultSubId = telephonyManager.getSubscriptionId(); 48 49 final SubscriptionManager subscriptionManager = 50 context.getSystemService(SubscriptionManager.class); 51 final List<SubscriptionInfo> subInfoList = 52 subscriptionManager.getAvailableSubscriptionInfoList(); 53 if (subInfoList == null) { 54 Log.i(TAG, "Subscription is not inited: " + subId); 55 return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId); 56 } 57 58 for (SubscriptionInfo subInfo : subInfoList) { 59 if ((subInfo != null) && (subInfo.getSubscriptionId() == subId)) { 60 return getNormalizedMobileTemplate(telephonyManager, subId); 61 } 62 } 63 Log.i(TAG, "Subscription is not active: " + subId); 64 return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId); 65 } 66 getNormalizedMobileTemplate( TelephonyManager telephonyManager, int subId)67 private static NetworkTemplate getNormalizedMobileTemplate( 68 TelephonyManager telephonyManager, int subId) { 69 final NetworkTemplate mobileTemplate = getMobileTemplateForSubId(telephonyManager, subId); 70 final String[] mergedSubscriberIds = telephonyManager 71 .createForSubscriptionId(subId).getMergedImsisFromGroup(); 72 if (ArrayUtils.isEmpty(mergedSubscriberIds)) { 73 Log.i(TAG, "mergedSubscriberIds is null."); 74 return mobileTemplate; 75 } 76 77 return normalizeMobileTemplate(mobileTemplate, mergedSubscriberIds); 78 } 79 normalizeMobileTemplate( @onNull NetworkTemplate template, @NonNull String[] merged)80 private static NetworkTemplate normalizeMobileTemplate( 81 @NonNull NetworkTemplate template, @NonNull String[] merged) { 82 if (template.getSubscriberIds().isEmpty()) return template; 83 // The input template should have at most 1 subscriberId. 84 final String subscriberId = template.getSubscriberIds().iterator().next(); 85 // In some rare cases (e.g. b/243015487), merged subscriberId list might contain 86 // duplicated items. Deduplication for better error handling. 87 final ArraySet mergedSet = new ArraySet(merged); 88 if (mergedSet.size() != merged.length) { 89 Log.wtf(TAG, "Duplicated merged list detected: " + Arrays.toString(merged)); 90 } 91 if (mergedSet.contains(subscriberId)) { 92 // Requested template subscriber is part of the merge group; return 93 // a template that matches all merged subscribers. 94 return new NetworkTemplate.Builder(template.getMatchRule()) 95 .setSubscriberIds(mergedSet) 96 .setMeteredness(template.getMeteredness()).build(); 97 } 98 99 return template; 100 } 101 getMobileTemplateForSubId( TelephonyManager telephonyManager, int subId)102 public static NetworkTemplate getMobileTemplateForSubId( 103 TelephonyManager telephonyManager, int subId) { 104 // Create template that matches any mobile network when the subscriberId is null. 105 String subscriberId = telephonyManager.getSubscriberId(subId); 106 return subscriberId != null 107 ? new NetworkTemplate.Builder(NetworkTemplate.MATCH_CARRIER) 108 .setSubscriberIds(Set.of(subscriberId)) 109 .setMeteredness(NetworkStats.METERED_YES) 110 .build() 111 : new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE) 112 .setMeteredness(NetworkStats.METERED_YES) 113 .build(); 114 } 115 } 116