1 /*
2  * Copyright 2018 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.internal.telephony.dataconnection;
18 
19 import android.annotation.NonNull;
20 import android.content.BroadcastReceiver;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.ServiceConnection;
26 import android.content.pm.PackageManager;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Message;
30 import android.os.PersistableBundle;
31 import android.os.Registrant;
32 import android.os.RegistrantList;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.telephony.AccessNetworkConstants.AccessNetworkType;
36 import android.telephony.Annotation.ApnType;
37 import android.telephony.CarrierConfigManager;
38 import android.telephony.data.ApnSetting;
39 import android.telephony.data.IQualifiedNetworksService;
40 import android.telephony.data.IQualifiedNetworksServiceCallback;
41 import android.telephony.data.QualifiedNetworksService;
42 import android.text.TextUtils;
43 import android.util.SparseArray;
44 
45 import com.android.internal.telephony.Phone;
46 import com.android.internal.util.IndentingPrintWriter;
47 import com.android.telephony.Rlog;
48 
49 import java.io.FileDescriptor;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.List;
53 import java.util.stream.Collectors;
54 
55 /**
56  * Access network manager manages the qualified/available networks for mobile data connection.
57  * It binds to the vendor's qualified networks service and actively monitors the qualified
58  * networks changes.
59  */
60 public class AccessNetworksManager extends Handler {
61     private static final String TAG = AccessNetworksManager.class.getSimpleName();
62     private static final boolean DBG = false;
63 
64     private static final int[] SUPPORTED_APN_TYPES = {
65             ApnSetting.TYPE_DEFAULT,
66             ApnSetting.TYPE_MMS,
67             ApnSetting.TYPE_FOTA,
68             ApnSetting.TYPE_IMS,
69             ApnSetting.TYPE_CBS,
70             ApnSetting.TYPE_SUPL,
71             ApnSetting.TYPE_EMERGENCY
72     };
73 
74     private static final int EVENT_BIND_QUALIFIED_NETWORKS_SERVICE = 1;
75 
76     private final Phone mPhone;
77 
78     private final CarrierConfigManager mCarrierConfigManager;
79 
80     private IQualifiedNetworksService mIQualifiedNetworksService;
81 
82     private AccessNetworksManagerDeathRecipient mDeathRecipient;
83 
84     private String mTargetBindingPackageName;
85 
86     private QualifiedNetworksServiceConnection mServiceConnection;
87 
88     // Available networks. Key is the APN type.
89     private final SparseArray<int[]> mAvailableNetworks = new SparseArray<>();
90 
91     private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList();
92 
93     private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() {
94         @Override
95         public void onReceive(Context context, Intent intent) {
96             final String action = intent.getAction();
97             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)
98                     && mPhone.getPhoneId() == intent.getIntExtra(
99                     CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) {
100                 // We should wait for carrier config changed event because the target binding
101                 // package name can come from the carrier config. Note that we still get this event
102                 // even when SIM is absent.
103                 if (DBG) log("Carrier config changed. Try to bind qualified network service.");
104                 sendEmptyMessage(EVENT_BIND_QUALIFIED_NETWORKS_SERVICE);
105             }
106         }
107     };
108 
109     /**
110      * Represents qualified network types list on a specific APN type.
111      */
112     public static class QualifiedNetworks {
113         public final @ApnType int apnType;
114         // The qualified networks in preferred order. Each network is a AccessNetworkType.
115         public final int[] qualifiedNetworks;
QualifiedNetworks(@pnType int apnType, int[] qualifiedNetworks)116         public QualifiedNetworks(@ApnType int apnType, int[] qualifiedNetworks) {
117             this.apnType = apnType;
118             this.qualifiedNetworks = qualifiedNetworks;
119         }
120 
121         @Override
toString()122         public String toString() {
123             List<String> accessNetworkStrings = new ArrayList<>();
124             for (int network : qualifiedNetworks) {
125                 accessNetworkStrings.add(AccessNetworkType.toString(network));
126             }
127             return "[QualifiedNetworks: apnType="
128                     + ApnSetting.getApnTypeString(apnType)
129                     + ", networks="
130                     + Arrays.stream(qualifiedNetworks)
131                     .mapToObj(type -> AccessNetworkType.toString(type))
132                     .collect(Collectors.joining(","))
133                     + "]";
134         }
135     }
136 
137     private class AccessNetworksManagerDeathRecipient implements IBinder.DeathRecipient {
138         @Override
binderDied()139         public void binderDied() {
140             // TODO: try to rebind the service.
141             loge("QualifiedNetworksService(" + mTargetBindingPackageName + ") died.");
142         }
143     }
144 
145     private final class QualifiedNetworksServiceConnection implements ServiceConnection {
146         @Override
onServiceConnected(ComponentName name, IBinder service)147         public void onServiceConnected(ComponentName name, IBinder service) {
148             if (DBG) log("onServiceConnected " + name);
149             mIQualifiedNetworksService = IQualifiedNetworksService.Stub.asInterface(service);
150             mDeathRecipient = new AccessNetworksManagerDeathRecipient();
151 
152             try {
153                 service.linkToDeath(mDeathRecipient, 0 /* flags */);
154                 mIQualifiedNetworksService.createNetworkAvailabilityProvider(mPhone.getPhoneId(),
155                         new QualifiedNetworksServiceCallback());
156             } catch (RemoteException e) {
157                 mDeathRecipient.binderDied();
158                 loge("Remote exception. " + e);
159             }
160         }
161         @Override
onServiceDisconnected(ComponentName name)162         public void onServiceDisconnected(ComponentName name) {
163             if (DBG) log("onServiceDisconnected " + name);
164             mTargetBindingPackageName = null;
165         }
166     }
167 
168     private final class QualifiedNetworksServiceCallback extends
169             IQualifiedNetworksServiceCallback.Stub {
170         @Override
onQualifiedNetworkTypesChanged(int apnTypes, int[] qualifiedNetworkTypes)171         public void onQualifiedNetworkTypesChanged(int apnTypes, int[] qualifiedNetworkTypes) {
172             log("onQualifiedNetworkTypesChanged. apnTypes = ["
173                     + ApnSetting.getApnTypesStringFromBitmask(apnTypes)
174                     + "], networks = [" + Arrays.stream(qualifiedNetworkTypes)
175                     .mapToObj(i -> AccessNetworkType.toString(i)).collect(Collectors.joining(","))
176                     + "]");
177             List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>();
178             for (int supportedApnType : SUPPORTED_APN_TYPES) {
179                 if ((apnTypes & supportedApnType) == supportedApnType) {
180                     // TODO: Verify the preference from data settings manager to make sure the order
181                     // of the networks do not violate users/carrier's preference.
182                     if (mAvailableNetworks.get(supportedApnType) != null) {
183                         if (Arrays.equals(mAvailableNetworks.get(supportedApnType),
184                                 qualifiedNetworkTypes)) {
185                             log("Available networks for "
186                                     + ApnSetting.getApnTypesStringFromBitmask(supportedApnType)
187                                     + " not changed.");
188                             continue;
189                         }
190                     }
191                     mAvailableNetworks.put(supportedApnType, qualifiedNetworkTypes);
192                     qualifiedNetworksList.add(new QualifiedNetworks(supportedApnType,
193                             qualifiedNetworkTypes));
194                 }
195             }
196 
197             if (!qualifiedNetworksList.isEmpty()) {
198                 mQualifiedNetworksChangedRegistrants.notifyResult(qualifiedNetworksList);
199             }
200         }
201     }
202 
203     /**
204      * Constructor
205      *
206      * @param phone The phone object
207      */
AccessNetworksManager(Phone phone)208     public AccessNetworksManager(Phone phone) {
209         mPhone = phone;
210         mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService(
211                 Context.CARRIER_CONFIG_SERVICE);
212 
213         IntentFilter intentFilter = new IntentFilter();
214         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
215         try {
216             Context contextAsUser = phone.getContext().createPackageContextAsUser(
217                 phone.getContext().getPackageName(), 0, UserHandle.ALL);
218             contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter,
219                 null /* broadcastPermission */, null);
220         } catch (PackageManager.NameNotFoundException e) {
221             Rlog.e(TAG, "Package name not found: " + e.getMessage());
222         }
223         sendEmptyMessage(EVENT_BIND_QUALIFIED_NETWORKS_SERVICE);
224     }
225 
226     /**
227      * Handle message events
228      *
229      * @param msg The message to handle
230      */
231     @Override
handleMessage(Message msg)232     public void handleMessage(Message msg) {
233         switch (msg.what) {
234             case EVENT_BIND_QUALIFIED_NETWORKS_SERVICE:
235                 bindQualifiedNetworksService();
236                 break;
237             default:
238                 loge("Unhandled event " + msg.what);
239         }
240     }
241 
242     /**
243      * Find the qualified network service from configuration and binds to it. It reads the
244      * configuration from carrier config if it exists. If not, read it from resources.
245      */
bindQualifiedNetworksService()246     private void bindQualifiedNetworksService() {
247         Intent intent = null;
248         String packageName = getQualifiedNetworksServicePackageName();
249         String className = getQualifiedNetworksServiceClassName();
250 
251         if (DBG) log("Qualified network service package = " + packageName);
252         if (TextUtils.isEmpty(packageName)) {
253             loge("Can't find the binding package");
254             return;
255         }
256 
257         if (TextUtils.isEmpty(className)) {
258             intent = new Intent(QualifiedNetworksService.QUALIFIED_NETWORKS_SERVICE_INTERFACE);
259             intent.setPackage(packageName);
260         } else {
261             ComponentName cm = new ComponentName(packageName, className);
262             intent = new Intent(QualifiedNetworksService.QUALIFIED_NETWORKS_SERVICE_INTERFACE)
263                     .setComponent(cm);
264         }
265 
266         if (TextUtils.equals(packageName, mTargetBindingPackageName)) {
267             if (DBG) log("Service " + packageName + " already bound or being bound.");
268             return;
269         }
270 
271         if (mIQualifiedNetworksService != null
272                 && mIQualifiedNetworksService.asBinder().isBinderAlive()) {
273             // Remove the network availability updater and then unbind the service.
274             try {
275                 mIQualifiedNetworksService.removeNetworkAvailabilityProvider(mPhone.getPhoneId());
276             } catch (RemoteException e) {
277                 loge("Cannot remove network availability updater. " + e);
278             }
279 
280             mPhone.getContext().unbindService(mServiceConnection);
281         }
282 
283         try {
284             mServiceConnection = new QualifiedNetworksServiceConnection();
285             log("bind to " + packageName);
286             if (!mPhone.getContext().bindService(intent, mServiceConnection,
287                         Context.BIND_AUTO_CREATE)) {
288                 loge("Cannot bind to the qualified networks service.");
289                 return;
290             }
291             mTargetBindingPackageName = packageName;
292         } catch (Exception e) {
293             loge("Cannot bind to the qualified networks service. Exception: " + e);
294         }
295     }
296 
297     /**
298      * Get the qualified network service package.
299      *
300      * @return package name of the qualified networks service package. Return empty string when in
301      * legacy mode (i.e. Dedicated IWLAN data/network service is not supported).
302      */
getQualifiedNetworksServicePackageName()303     private String getQualifiedNetworksServicePackageName() {
304         // Read package name from the resource
305         String packageName = mPhone.getContext().getResources().getString(
306                 com.android.internal.R.string.config_qualified_networks_service_package);
307 
308         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());
309 
310         if (b != null) {
311             // If carrier config overrides it, use the one from carrier config
312             String carrierConfigPackageName =  b.getString(CarrierConfigManager
313                     .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING);
314             if (!TextUtils.isEmpty(carrierConfigPackageName)) {
315                 if (DBG) log("Found carrier config override " + carrierConfigPackageName);
316                 packageName = carrierConfigPackageName;
317             }
318         }
319 
320         return packageName;
321     }
322 
323     /**
324      * Get the qualified network service class name.
325      *
326      * @return class name of the qualified networks service package.
327      */
getQualifiedNetworksServiceClassName()328     private String getQualifiedNetworksServiceClassName() {
329         // Read package name from the resource
330         String className = mPhone.getContext().getResources().getString(
331                 com.android.internal.R.string.config_qualified_networks_service_class);
332 
333         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());
334 
335         if (b != null) {
336             // If carrier config overrides it, use the one from carrier config
337             String carrierConfigClassName =  b.getString(CarrierConfigManager
338                     .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING);
339             if (!TextUtils.isEmpty(carrierConfigClassName)) {
340                 if (DBG) log("Found carrier config override " + carrierConfigClassName);
341                 className = carrierConfigClassName;
342             }
343         }
344 
345         return className;
346     }
347 
getQualifiedNetworksList()348     private @NonNull List<QualifiedNetworks> getQualifiedNetworksList() {
349         List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>();
350         for (int i = 0; i < mAvailableNetworks.size(); i++) {
351             qualifiedNetworksList.add(new QualifiedNetworks(mAvailableNetworks.keyAt(i),
352                     mAvailableNetworks.valueAt(i)));
353         }
354 
355         return qualifiedNetworksList;
356     }
357 
358     /**
359      * Register for qualified networks changed event.
360      *
361      * @param h The target to post the event message to.
362      * @param what The event.
363      */
registerForQualifiedNetworksChanged(Handler h, int what)364     public void registerForQualifiedNetworksChanged(Handler h, int what) {
365         if (h != null) {
366             Registrant r = new Registrant(h, what, null);
367             mQualifiedNetworksChangedRegistrants.add(r);
368 
369             // Notify for the first time if there is already something in the available network
370             // list.
371             if (mAvailableNetworks.size() != 0) {
372                 r.notifyResult(getQualifiedNetworksList());
373             }
374         }
375     }
376 
377     /**
378      * Unregister for qualified networks changed event.
379      *
380      * @param h The handler
381      */
unregisterForQualifiedNetworksChanged(Handler h)382     public void unregisterForQualifiedNetworksChanged(Handler h) {
383         if (h != null) {
384             mQualifiedNetworksChangedRegistrants.remove(h);
385         }
386     }
387 
388     /**
389      * Dump the state of transport manager
390      *
391      * @param fd File descriptor
392      * @param pw Print writer
393      * @param args Arguments
394      */
dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args)395     public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
396         pw.println("AccessNetworksManager:");
397         pw.increaseIndent();
398         pw.println("Available networks:");
399         pw.increaseIndent();
400 
401         for (int i = 0; i < mAvailableNetworks.size(); i++) {
402             pw.println("APN type " + ApnSetting.getApnTypeString(mAvailableNetworks.keyAt(i))
403                     + ": [" + Arrays.stream(mAvailableNetworks.valueAt(i))
404                     .mapToObj(type -> AccessNetworkType.toString(type))
405                     .collect(Collectors.joining(",")) + "]");
406         }
407         pw.decreaseIndent();
408         pw.decreaseIndent();
409     }
410 
log(String s)411     private void log(String s) {
412         Rlog.d(TAG, s);
413     }
414 
loge(String s)415     private void loge(String s) {
416         Rlog.e(TAG, s);
417     }
418 
419 }
420