• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package android.service.carrier;
16 
17 import android.annotation.CallSuper;
18 import android.annotation.Nullable;
19 import android.annotation.SuppressLint;
20 import android.app.Service;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.Bundle;
24 import android.os.IBinder;
25 import android.os.PersistableBundle;
26 import android.os.ResultReceiver;
27 import android.telephony.SubscriptionManager;
28 import android.telephony.TelephonyRegistryManager;
29 import android.util.Log;
30 
31 import com.android.internal.util.ArrayUtils;
32 
33 import java.io.FileDescriptor;
34 import java.io.PrintWriter;
35 
36 /**
37  * A service that exposes carrier-specific functionality to the system.
38  * <p>
39  * To extend this class, you must declare the service in your manifest file to require the
40  * {@link android.Manifest.permission#BIND_CARRIER_SERVICES} permission and include an intent
41  * filter with the {@link #CARRIER_SERVICE_INTERFACE}. If the service should have a long-lived
42  * binding, set <code>android.service.carrier.LONG_LIVED_BINDING</code> to <code>true</code> in the
43  * service's metadata. For example:
44  * </p>
45  *
46  * <pre>{@code
47  * <service android:name=".MyCarrierService"
48  *       android:label="@string/service_name"
49  *       android:permission="android.permission.BIND_CARRIER_SERVICES">
50  *  <intent-filter>
51  *      <action android:name="android.service.carrier.CarrierService" />
52  *  </intent-filter>
53  *  <meta-data android:name="android.service.carrier.LONG_LIVED_BINDING"
54  *             android:value="true" />
55  * </service>
56  * }</pre>
57  */
58 public abstract class CarrierService extends Service {
59 
60     private static final String LOG_TAG = "CarrierService";
61 
62     public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
63 
64     private final ICarrierService.Stub mStubWrapper;
65 
CarrierService()66     public CarrierService() {
67         mStubWrapper = new ICarrierServiceWrapper();
68     }
69 
70     /**
71      * Override this method to set carrier configuration.
72      * <p>
73      * This method will be called by telephony services to get carrier-specific configuration
74      * values. The returned config will be saved by the system until,
75      * <ol>
76      * <li>The carrier app package is updated, or</li>
77      * <li>The carrier app requests a reload with
78      * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
79      * notifyConfigChangedForSubId}.</li>
80      * </ol>
81      * This method can be called after a SIM card loads, which may be before or after boot.
82      * </p>
83      * <p>
84      * This method should not block for a long time. If expensive operations (e.g. network access)
85      * are required, this method can schedule the work and return null. Then, use
86      * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
87      * notifyConfigChangedForSubId} to trigger a reload when the config is ready.
88      * </p>
89      * <p>
90      * Implementations should use the keys defined in {@link android.telephony.CarrierConfigManager
91      * CarrierConfigManager}. Any configuration values not set in the returned {@link
92      * PersistableBundle} may be overridden by the system's default configuration service.
93      * </p>
94      *
95      * @param id contains details about the current carrier that can be used to decide what
96      *           configuration values to return. Instead of using details like MCCMNC to decide
97      *           current carrier, it also contains subscription carrier id
98      *           {@link android.telephony.TelephonyManager#getSimCarrierId()}, a platform-wide
99      *           unique identifier for each carrier, CarrierConfigService can directly use carrier
100      *           id as the key to look up the carrier info.
101      * @return a {@link PersistableBundle} object containing the configuration or null if default
102      *         values should be used.
103      * @deprecated use {@link #onLoadConfig(int, CarrierIdentifier)} instead.
104      */
105     @Deprecated
onLoadConfig(CarrierIdentifier id)106     public abstract PersistableBundle onLoadConfig(CarrierIdentifier id);
107 
108     /**
109      * Override this method to set carrier configuration on the given {@code subscriptionId}.
110      * <p>
111      * This method will be called by telephony services to get carrier-specific configuration
112      * values. The returned config will be saved by the system until,
113      * <ol>
114      * <li>The carrier app package is updated, or</li>
115      * <li>The carrier app requests a reload with
116      * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
117      * notifyConfigChangedForSubId}.</li>
118      * </ol>
119      * This method can be called after a SIM card loads, which may be before or after boot.
120      * </p>
121      * <p>
122      * This method should not block for a long time. If expensive operations (e.g. network access)
123      * are required, this method can schedule the work and return null. Then, use
124      * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
125      * notifyConfigChangedForSubId} to trigger a reload when the config is ready.
126      * </p>
127      * <p>
128      * Implementations should use the keys defined in {@link android.telephony.CarrierConfigManager
129      * CarrierConfigManager}. Any configuration values not set in the returned {@link
130      * PersistableBundle} may be overridden by the system's default configuration service.
131      * </p>
132      * <p>
133      * By default, this method just calls {@link #onLoadConfig(CarrierIdentifier)} with specified
134      * CarrierIdentifier {@code id}. Carrier app with target SDK
135      * {@link android.os.Build.VERSION_CODES#TIRAMISU} and above should override this method to
136      * load carrier configuration on the given {@code subscriptionId}.
137      * Note that {@link #onLoadConfig(CarrierIdentifier)} is still called prior to
138      * {@link android.os.Build.VERSION_CODES#TIRAMISU}.
139      * </p>
140      *
141      * @param subscriptionId the subscription on which the carrier app should load configuration
142      * @param id contains details about the current carrier that can be used to decide what
143      *           configuration values to return. Instead of using details like MCCMNC to decide
144      *           current carrier, it also contains subscription carrier id
145      *           {@link android.telephony.TelephonyManager#getSimCarrierId()}, a platform-wide
146      *           unique identifier for each carrier, CarrierConfigService can directly use carrier
147      *           id as the key to look up the carrier info.
148      * @return a {@link PersistableBundle} object containing the configuration or null if default
149      *         values should be used.
150      */
151     @SuppressLint("NullableCollection")
152     @Nullable
onLoadConfig(int subscriptionId, @Nullable CarrierIdentifier id)153     public PersistableBundle onLoadConfig(int subscriptionId, @Nullable CarrierIdentifier id) {
154         return onLoadConfig(id);
155     }
156 
157     /**
158      * Informs the system of an intentional upcoming carrier network change by
159      * a carrier app. This call is optional and is only used to allow the
160      * system to provide alternative UI while telephony is performing an action
161      * that may result in intentional, temporary network lack of connectivity.
162      * <p>
163      * Based on the active parameter passed in, this method will either show or
164      * hide the alternative UI. There is no timeout associated with showing
165      * this UX, so a carrier app must be sure to call with active set to false
166      * sometime after calling with it set to true.
167      * <p>
168      * Requires Permission: calling app has carrier privileges.
169      *
170      * @param active Whether the carrier network change is or shortly will be
171      *               active. Set this value to true to begin showing
172      *               alternative UI and false to stop.
173      * @see android.telephony.TelephonyManager#hasCarrierPrivileges
174      * @deprecated use {@link #notifyCarrierNetworkChange(int, boolean)} instead.
175      *             With no parameter to specify the subscription, this API will
176      *             apply to all subscriptions that the carrier app has carrier
177      *             privileges on.
178      */
179     @Deprecated
notifyCarrierNetworkChange(boolean active)180     public final void notifyCarrierNetworkChange(boolean active) {
181         TelephonyRegistryManager telephonyRegistryMgr =
182             (TelephonyRegistryManager) this.getSystemService(
183                 Context.TELEPHONY_REGISTRY_SERVICE);
184         if (telephonyRegistryMgr != null) {
185             telephonyRegistryMgr.notifyCarrierNetworkChange(active);
186         }
187     }
188 
189     /**
190      * Informs the system of an intentional upcoming carrier network change by a carrier app on the
191      * given {@code subscriptionId}. This call is optional and is only used to allow the system to
192      * provide alternative UI while telephony is performing an action that may result in
193      * intentional, temporary network lack of connectivity.
194      *
195      * <p>Based on the active parameter passed in, this method will either show or hide the
196      * alternative UI. There is no timeout associated with showing this UX, so a carrier app must
197      * be sure to call with active set to false sometime after calling with it set to true.
198      *
199      * <p>Requires Permission: calling app has carrier privileges.
200      *
201      * @param subscriptionId the subscription of the carrier network that trigger the change.
202      * @param active whether the carrier network change is or shortly will be active. Set this
203      *               value to true to begin showing alternative UI and false to stop.
204      * @see android.telephony.TelephonyManager#hasCarrierPrivileges
205      */
notifyCarrierNetworkChange(int subscriptionId, boolean active)206     public final void notifyCarrierNetworkChange(int subscriptionId, boolean active) {
207         TelephonyRegistryManager telephonyRegistryMgr = this.getSystemService(
208                 TelephonyRegistryManager.class);
209         if (telephonyRegistryMgr != null) {
210             telephonyRegistryMgr.notifyCarrierNetworkChange(subscriptionId, active);
211         }
212     }
213 
214     /**
215      * If overriding this method, call through to the super method for any unknown actions.
216      * {@inheritDoc}
217      */
218     @Override
219     @CallSuper
onBind(Intent intent)220     public IBinder onBind(Intent intent) {
221         return mStubWrapper;
222     }
223 
224     /**
225      * A wrapper around ICarrierService that forwards calls to implementations of
226      * {@link CarrierService}.
227      * @hide
228      */
229     public class ICarrierServiceWrapper extends ICarrierService.Stub {
230         /** @hide */
231         public static final int RESULT_OK = 0;
232         /** @hide */
233         public static final int RESULT_ERROR = 1;
234         /** @hide */
235         public static final String KEY_CONFIG_BUNDLE = "config_bundle";
236 
237         @Override
getCarrierConfig(int phoneId, CarrierIdentifier id, ResultReceiver result)238         public void getCarrierConfig(int phoneId, CarrierIdentifier id, ResultReceiver result) {
239             try {
240                 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
241                 int[] subIds = SubscriptionManager.getSubId(phoneId);
242                 if (!ArrayUtils.isEmpty(subIds)) {
243                     // There should be at most one active subscription mapping to the phoneId.
244                     subId = subIds[0];
245                 }
246                 Bundle data = new Bundle();
247                 data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(subId, id));
248                 result.send(RESULT_OK, data);
249             } catch (Exception e) {
250                 Log.e(LOG_TAG, "Error in onLoadConfig: " + e.getMessage(), e);
251                 result.send(RESULT_ERROR, null);
252             }
253         }
254 
255         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)256         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
257             CarrierService.this.dump(fd, pw, args);
258         }
259     }
260 }
261