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