blob: 0c34c5f04bc19abe5995d807806fbfe683a21252 [file] [log] [blame]
Jonathan Basseri6465afd2015-02-25 13:05:57 -08001/**
2 * Copyright (c) 2015, 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
Jonathan Basseri6465afd2015-02-25 13:05:57 -080017package com.android.phone;
18
19import static android.Manifest.permission.READ_PHONE_STATE;
20import static com.android.internal.telephony.uicc.IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED;
21
Jonathan Basseri11f89572015-05-05 11:57:39 -070022import android.annotation.NonNull;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080023import android.app.ActivityManagerNative;
24import android.content.BroadcastReceiver;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.ServiceConnection;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070030import android.content.pm.PackageInfo;
Jonathan Basseric31f1f32015-05-12 10:13:03 -070031import android.content.pm.PackageManager;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080032import android.database.sqlite.SQLiteDatabase;
33import android.database.sqlite.SQLiteOpenHelper;
34import android.os.AsyncResult;
Junda Liu43d723a2015-05-12 17:23:45 -070035import android.os.Binder;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080036import android.os.Handler;
37import android.os.IBinder;
38import android.os.Message;
Jonathan Basseric31f1f32015-05-12 10:13:03 -070039import android.os.PersistableBundle;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080040import android.os.RemoteException;
41import android.os.ServiceManager;
42import android.os.UserHandle;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080043import android.service.carrier.CarrierIdentifier;
Zach Johnson36d7aab2015-05-22 15:43:00 -070044import android.service.carrier.CarrierService;
45import android.service.carrier.ICarrierService;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080046import android.telephony.CarrierConfigManager;
47import android.telephony.SubscriptionManager;
48import android.telephony.TelephonyManager;
49import android.util.Log;
50
51import com.android.internal.telephony.ICarrierConfigLoader;
52import com.android.internal.telephony.IccCardConstants;
53import com.android.internal.telephony.Phone;
54import com.android.internal.telephony.PhoneConstants;
55import com.android.internal.telephony.PhoneFactory;
56import com.android.internal.telephony.TelephonyIntents;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070057import com.android.internal.util.FastXmlSerializer;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080058
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070059import org.xmlpull.v1.XmlPullParser;
60import org.xmlpull.v1.XmlPullParserException;
61import org.xmlpull.v1.XmlPullParserFactory;
62
63import java.io.File;
Junda Liu43d723a2015-05-12 17:23:45 -070064import java.io.FileDescriptor;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070065import java.io.FileInputStream;
66import java.io.FileNotFoundException;
67import java.io.FileOutputStream;
68import java.io.IOException;
Junda Liu43d723a2015-05-12 17:23:45 -070069import java.io.PrintWriter;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080070import java.util.List;
71
72/**
73 * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
Jonathan Basserib919e932015-05-27 16:53:08 +000074 * TODO: implement persist cache
Jonathan Basseri6465afd2015-02-25 13:05:57 -080075 * TODO: handle package install/uninstall events
76 */
77
78public class CarrierConfigLoader extends ICarrierConfigLoader.Stub {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070079 private static final String LOG_TAG = "CarrierConfigLoader";
Jonathan Basseri6465afd2015-02-25 13:05:57 -080080 // Package name for default carrier config app, bundled with system image.
81 private static final String DEFAULT_CARRIER_CONFIG_PACKAGE = "com.android.carrierconfig";
82
83 /** The singleton instance. */
84 private static CarrierConfigLoader sInstance;
85 // The context for phone app, passed from PhoneGlobals.
86 private Context mContext;
87 // Carrier configs from default app, indexed by phoneID.
Jonathan Basseric31f1f32015-05-12 10:13:03 -070088 private PersistableBundle[] mConfigFromDefaultApp;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080089 // Carrier configs from privileged carrier config app, indexed by phoneID.
Jonathan Basseric31f1f32015-05-12 10:13:03 -070090 private PersistableBundle[] mConfigFromCarrierApp;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080091 // Service connection for binding to config app.
Zach Johnson36d7aab2015-05-22 15:43:00 -070092 private CarrierServiceConnection[] mServiceConnection;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080093
94 // Broadcast receiver for SIM and pkg intents, register intent filter in constructor.
95 private final BroadcastReceiver mReceiver = new ConfigLoaderBroadcastReceiver();
96
97 // Message codes; see mHandler below.
98 // Request from SubscriptionInfoUpdater when SIM becomes absent or error.
99 private static final int EVENT_CLEAR_CONFIG = 0;
Jonathan Basserib919e932015-05-27 16:53:08 +0000100 // Request from SubscriptionInfoUpdater to update config.
101 private static final int EVENT_UPDATE_CONFIG = 1;
102 // Request from carrier app to reload config.
103 private static final int EVENT_RELOAD_CONFIG = 2;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800104 // Has connected to default app.
105 private static final int EVENT_CONNECTED_TO_DEFAULT = 3;
106 // Has connected to carrier app.
107 private static final int EVENT_CONNECTED_TO_CARRIER = 4;
108 // Config has been loaded from default app.
109 private static final int EVENT_LOADED_FROM_DEFAULT = 5;
110 // Config has been loaded from carrier app.
111 private static final int EVENT_LOADED_FROM_CARRIER = 6;
112
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700113 // Tags used for saving and restoring XML documents.
114 private static final String TAG_DOCUMENT = "carrier_config";
115 private static final String TAG_VERSION = "package_version";
116 private static final String TAG_BUNDLE = "bundle_data";
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800117
118 // Handler to process various events.
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700119 //
Jonathan Basserib919e932015-05-27 16:53:08 +0000120 // For each phoneId, state transition should be: default app bind->connected->loaded, carrier
121 // app (if exists) bind-> connected->loaded. At any time, at most one connection is active. If
122 // events are not in this order, previous connection will be unbind, so only latest event takes
123 // effect.
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700124 //
Jonathan Basserib919e932015-05-27 16:53:08 +0000125 // We broadcast config change when:
126 // 1. loaded from carrier app
127 // 2. loaded from default app if no carrier app
128 // 3. config cleared, possibly due to sim removed
129 // 4. bind or IPC error
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800130 private Handler mHandler = new Handler() {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700131 @Override
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800132 public void handleMessage(Message msg) {
133 int phoneId = msg.arg1;
134 log("mHandler: " + msg.what + " phoneId: " + phoneId);
135 CarrierIdentifier carrierId;
Zach Johnson36d7aab2015-05-22 15:43:00 -0700136 CarrierServiceConnection conn;
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700137 PersistableBundle config;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800138 switch (msg.what) {
139 case EVENT_CLEAR_CONFIG:
Junda Liu0486bdb2015-05-22 15:01:35 -0700140 if (mConfigFromDefaultApp[phoneId] == null &&
141 mConfigFromCarrierApp[phoneId] == null)
142 break;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800143 mConfigFromDefaultApp[phoneId] = null;
144 mConfigFromCarrierApp[phoneId] = null;
145 mServiceConnection[phoneId] = null;
146 broadcastConfigChangedIntent(phoneId);
147 break;
Jonathan Basserib919e932015-05-27 16:53:08 +0000148 case EVENT_UPDATE_CONFIG:
149 // Use persist cache to avoid loading from app.
150 // Fall through to next event if cache not hit.
151 case EVENT_RELOAD_CONFIG:
152 if (!bindToConfigPackage(DEFAULT_CARRIER_CONFIG_PACKAGE,
153 phoneId, EVENT_CONNECTED_TO_DEFAULT)) {
154 // Send bcast if bind fails
155 broadcastConfigChangedIntent(phoneId);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800156 }
157 break;
158
159 case EVENT_CONNECTED_TO_DEFAULT:
160 carrierId = getCarrierIdForPhoneId(phoneId);
Zach Johnson36d7aab2015-05-22 15:43:00 -0700161 conn = (CarrierServiceConnection) msg.obj;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800162 // If new service connection has been created, unbind.
163 if (mServiceConnection[phoneId] != conn || conn.service == null) {
164 mContext.unbindService(conn);
165 break;
166 }
167 try {
Zach Johnson36d7aab2015-05-22 15:43:00 -0700168 ICarrierService carrierService = ICarrierService.Stub
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700169 .asInterface(conn.service);
Zach Johnson36d7aab2015-05-22 15:43:00 -0700170 config = carrierService.getCarrierConfig(carrierId);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800171 mConfigFromDefaultApp[phoneId] = config;
Junda Liu9f2d2712015-05-15 14:22:45 -0700172 sendMessage(obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId, -1));
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800173 } catch (RemoteException ex) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700174 loge("Failed to get carrier config: " + ex.toString());
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800175 } finally {
176 mContext.unbindService(mServiceConnection[phoneId]);
177 }
178 break;
179
180 case EVENT_LOADED_FROM_DEFAULT:
Jonathan Basserib919e932015-05-27 16:53:08 +0000181 if (mServiceConnection[phoneId] == null) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800182 break;
183 }
Jonathan Basserib919e932015-05-27 16:53:08 +0000184 List<String> carrierPackageNames = TelephonyManager.from(mContext)
185 .getCarrierPackageNamesForIntentAndPhone(
Zach Johnsona9d689f2015-05-27 16:23:22 -0700186 new Intent(CarrierService.CONFIG_SERVICE_INTERFACE), phoneId);
Jonathan Basserib919e932015-05-27 16:53:08 +0000187 log("Found carrier config app: " + carrierPackageNames);
188 if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
189 if (!bindToConfigPackage(carrierPackageNames.get(0),
190 phoneId, EVENT_CONNECTED_TO_CARRIER)) {
Jonathan Basseri4ae2e7c2015-05-15 00:19:46 -0700191 broadcastConfigChangedIntent(phoneId);
192 }
Jonathan Basserib919e932015-05-27 16:53:08 +0000193 } else {
194 broadcastConfigChangedIntent(phoneId);
Jonathan Basseri4ae2e7c2015-05-15 00:19:46 -0700195 }
196 break;
197
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800198 case EVENT_CONNECTED_TO_CARRIER:
199 carrierId = getCarrierIdForPhoneId(phoneId);
Zach Johnson36d7aab2015-05-22 15:43:00 -0700200 conn = (CarrierServiceConnection) msg.obj;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800201 // If new service connection has been created, unbind.
202 if (mServiceConnection[phoneId] != conn ||
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700203 conn.service == null) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800204 mContext.unbindService(conn);
205 break;
206 }
207 try {
Zach Johnson36d7aab2015-05-22 15:43:00 -0700208 ICarrierService carrierService = ICarrierService.Stub
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700209 .asInterface(conn.service);
Zach Johnson36d7aab2015-05-22 15:43:00 -0700210 config = carrierService.getCarrierConfig(carrierId);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800211 mConfigFromCarrierApp[phoneId] = config;
Junda Liu9f2d2712015-05-15 14:22:45 -0700212 sendMessage(obtainMessage(EVENT_LOADED_FROM_CARRIER, phoneId, -1));
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800213 } catch (RemoteException ex) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700214 loge("Failed to get carrier config: " + ex.toString());
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800215 } finally {
216 mContext.unbindService(mServiceConnection[phoneId]);
217 }
218 break;
219
220 case EVENT_LOADED_FROM_CARRIER:
Jonathan Basserib919e932015-05-27 16:53:08 +0000221 if (mServiceConnection[phoneId] == null) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800222 break;
223 }
224 broadcastConfigChangedIntent(phoneId);
225 break;
226 }
227 }
228 };
229
230 /**
231 * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast
232 * receiver for relevant events.
233 */
234 private CarrierConfigLoader(Context context) {
235 mContext = context;
236
237 // Register for package updates.
238 IntentFilter triggers = new IntentFilter();
239 triggers.addAction(Intent.ACTION_PACKAGE_ADDED);
240 triggers.addAction(Intent.ACTION_PACKAGE_CHANGED);
241 triggers.addAction(Intent.ACTION_PACKAGE_REMOVED);
242 mContext.registerReceiver(mReceiver, triggers);
243
244 int numPhones = TelephonyManager.from(context).getPhoneCount();
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700245 mConfigFromDefaultApp = new PersistableBundle[numPhones];
246 mConfigFromCarrierApp = new PersistableBundle[numPhones];
Zach Johnson36d7aab2015-05-22 15:43:00 -0700247 mServiceConnection = new CarrierServiceConnection[numPhones];
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800248 // Make this service available through ServiceManager.
249 ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
250 log("CarrierConfigLoader has started");
251 }
252
253 /**
254 * Initialize the singleton CarrierConfigLoader instance.
255 *
256 * This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}.
257 */
258 /* package */
259 static CarrierConfigLoader init(Context context) {
260 synchronized (CarrierConfigLoader.class) {
261 if (sInstance == null) {
262 sInstance = new CarrierConfigLoader(context);
263 } else {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700264 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800265 }
266 return sInstance;
267 }
268 }
269
270 private void broadcastConfigChangedIntent(int phoneId) {
271 Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
272 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
273 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
274 ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700275 UserHandle.USER_ALL);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800276 }
277
278 /** Binds to the default or carrier config app. */
279 private boolean bindToConfigPackage(String pkgName, int phoneId, int eventId) {
280 log("Binding to " + pkgName + " for phone " + phoneId);
Zach Johnsona9d689f2015-05-27 16:23:22 -0700281 Intent carrierService = new Intent(CarrierService.CONFIG_SERVICE_INTERFACE);
Zach Johnson36d7aab2015-05-22 15:43:00 -0700282 carrierService.setPackage(pkgName);
283 mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800284 try {
Zach Johnson36d7aab2015-05-22 15:43:00 -0700285 return mContext.bindService(carrierService, mServiceConnection[phoneId],
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800286 Context.BIND_AUTO_CREATE);
287 } catch (SecurityException ex) {
288 return false;
289 }
290 }
291
292 private CarrierIdentifier getCarrierIdForPhoneId(int phoneId) {
293 String mcc = "";
294 String mnc = "";
295 String imsi = "";
296 String gid1 = "";
297 String gid2 = "";
298 String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId);
299 String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId);
Jonathan Basseri1fa437c2015-04-20 11:08:18 -0700300 // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC.
301 if (simOperator != null && simOperator.length() >= 3) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800302 mcc = simOperator.substring(0, 3);
303 mnc = simOperator.substring(3);
304 }
305 Phone phone = PhoneFactory.getPhone(phoneId);
306 if (phone != null) {
307 imsi = phone.getSubscriberId();
308 gid1 = phone.getGroupIdLevel1();
Junda Liu73183532015-05-14 13:55:40 -0700309 gid2 = phone.getGroupIdLevel2();
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800310 }
311
312 return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2);
313 }
314
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700315 /**
316 * Writes a bundle to an XML file.
317 *
318 * The bundle will be written to a file named after the package name and ICCID, so that it can
319 * be restored later with {@link @restoreConfigFromXml}. The XML output will include the bundle
Jonathan Basserib919e932015-05-27 16:53:08 +0000320 * and the current version of the specified package. In case of errors, no file will be written.
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700321 *
322 * @param packageName the name of the package from which we fetched this bundle.
323 * @param iccid the ICCID of the subscription for which this bundle was fetched.
324 * @param config the bundle to be written.
325 */
326 private void saveConfigToXml(String packageName, String iccid, PersistableBundle config) {
327 final String version = getPackageVersion(packageName);
328 if (version == null) {
329 loge("Failed to get package version for: " + packageName);
330 return;
331 }
332
333 FileOutputStream outFile = null;
334 try {
335 outFile = new FileOutputStream(
336 new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
337 FastXmlSerializer out = new FastXmlSerializer();
338 out.setOutput(outFile, "utf-8");
339 out.startDocument("utf-8", true);
340 out.startTag(null, TAG_DOCUMENT);
341 out.startTag(null, TAG_VERSION);
342 out.text(version);
343 out.endTag(null, TAG_VERSION);
344 out.startTag(null, TAG_BUNDLE);
345 config.saveToXml(out);
346 out.endTag(null, TAG_BUNDLE);
347 out.endTag(null, TAG_DOCUMENT);
348 out.endDocument();
349 out.flush();
350 outFile.close();
351 }
352 catch (IOException e) {
353 loge(e.toString());
354 }
355 catch (XmlPullParserException e) {
356 loge(e.toString());
357 }
358 }
359
360 /**
361 * Reads a bundle from an XML file.
362 *
363 * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved
Jonathan Basserib919e932015-05-27 16:53:08 +0000364 * config bundle for the given package and ICCID. If the saved config is for a different package
365 * version than the current version, then null will be returned.
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700366 *
367 * @param packageName the name of the package from which we fetched this bundle.
368 * @param iccid the ICCID of the subscription for which this bundle was fetched.
369 * @return the bundle from the XML file. Returns null if there is no saved config, the saved
370 * version does not match, or reading config fails.
371 */
372 private PersistableBundle restoreConfigFromXml(String packageName, String iccid) {
373 final String version = getPackageVersion(packageName);
374 if (version == null) {
375 loge("Failed to get package version for: " + packageName);
376 return null;
377 }
378
379 PersistableBundle restoredBundle = null;
380 FileInputStream inFile = null;
381 try {
382 inFile = new FileInputStream(
383 new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
384 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
385 parser.setInput(inFile, "utf-8");
386
387 int event;
388 while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) {
389
390 if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) {
391 String savedVersion = parser.nextText();
392 if (!version.equals(savedVersion)) {
393 log("Saved version mismatch: " + version + " vs " + savedVersion);
394 break;
395 }
396 }
397
398 if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) {
399 restoredBundle = PersistableBundle.restoreFromXml(parser);
400 }
401 }
402 inFile.close();
403 }
404 catch (FileNotFoundException e) {
405 loge(e.toString());
406 }
407 catch (XmlPullParserException e) {
408 loge(e.toString());
409 }
410 catch (IOException e) {
411 loge(e.toString());
412 }
413
414 return restoredBundle;
415 }
416
417 /** Builds a canonical file name for a config file. */
Jonathan Basserib919e932015-05-27 16:53:08 +0000418 private String getFilenameForConfig(String packageName, String iccid) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700419 return "carrierconfig-" + packageName + "-" + iccid + ".xml";
420 }
421
Jonathan Basserib919e932015-05-27 16:53:08 +0000422 /** Return the current version of a package, or null if the name is not found. */
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700423 private String getPackageVersion(String packageName) {
424 try {
425 PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
Jonathan Basserib919e932015-05-27 16:53:08 +0000426 return info.versionName;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700427 } catch (PackageManager.NameNotFoundException e) {
428 return null;
429 }
430 }
431
Jonathan Basserib919e932015-05-27 16:53:08 +0000432 @Override
433 public @NonNull PersistableBundle getConfigForSubId(int subId) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800434 int phoneId = SubscriptionManager.getPhoneId(subId);
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700435 PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800436 if (SubscriptionManager.isValidPhoneId(phoneId)) {
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700437 PersistableBundle config = mConfigFromDefaultApp[phoneId];
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700438 if (config != null)
439 retConfig.putAll(config);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800440 config = mConfigFromCarrierApp[phoneId];
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700441 if (config != null)
442 retConfig.putAll(config);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800443 }
444 return retConfig;
445 }
446
447 @Override
448 public void reloadCarrierConfigForSubId(int subId) {
449 int phoneId = SubscriptionManager.getPhoneId(subId);
Jonathan Basserib919e932015-05-27 16:53:08 +0000450 if (SubscriptionManager.isValidPhoneId(phoneId)) {
451 mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELOAD_CONFIG, phoneId, -1));
452 } else {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800453 log("Ignore invalid phoneId: " + phoneId + " for subId: " + subId);
454 }
455 }
456
457 @Override
458 public void updateConfigForPhoneId(int phoneId, String simState) {
459 log("update config for phoneId: " + phoneId + " simState: " + simState);
460 if (!SubscriptionManager.isValidPhoneId(phoneId)) {
461 return;
462 }
463 // requires Java 7 for switch on string.
464 switch (simState) {
465 case IccCardConstants.INTENT_VALUE_ICC_ABSENT:
466 case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR:
467 case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN:
Junda Liu9f2d2712015-05-15 14:22:45 -0700468 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1));
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800469 break;
470 case IccCardConstants.INTENT_VALUE_ICC_LOADED:
471 case IccCardConstants.INTENT_VALUE_ICC_LOCKED:
Jonathan Basserib919e932015-05-27 16:53:08 +0000472 mHandler.sendMessage(mHandler.obtainMessage(EVENT_UPDATE_CONFIG, phoneId, -1));
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800473 break;
474 }
475 }
476
Junda Liu43d723a2015-05-12 17:23:45 -0700477 @Override
478 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
479 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
480 != PackageManager.PERMISSION_GRANTED) {
481 pw.println("Permission Denial: can't dump carrierconfig from from pid="
482 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
483 return;
484 }
485 pw.println("CarrierConfigLoader: " + this);
486 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
487 pw.println(" Phone Id=" + i);
488 pw.println(" mConfigFromDefaultApp=" + mConfigFromDefaultApp[i]);
489 pw.println(" mConfigFromCarrierApp=" + mConfigFromCarrierApp[i]);
490 }
491 }
492
Zach Johnson36d7aab2015-05-22 15:43:00 -0700493 private class CarrierServiceConnection implements ServiceConnection {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800494 int phoneId;
495 int eventId;
496 IBinder service;
497
Zach Johnson36d7aab2015-05-22 15:43:00 -0700498 public CarrierServiceConnection(int phoneId, int eventId) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800499 this.phoneId = phoneId;
500 this.eventId = eventId;
501 }
502
503 @Override
504 public void onServiceConnected(ComponentName name, IBinder service) {
505 log("Connected to config app: " + name.flattenToString());
506 this.service = service;
507 mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this));
508 }
509
510 @Override
511 public void onServiceDisconnected(ComponentName name) {
512 this.service = null;
513 }
514 }
515
516 private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver {
517 @Override
518 public void onReceive(Context context, Intent intent) {
519 String action = intent.getAction();
520 log("Receive action: " + action);
521 }
522 }
523
524 private static void log(String msg) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700525 Log.d(LOG_TAG, msg);
526 }
527
528 private static void loge(String msg) {
529 Log.e(LOG_TAG, msg);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800530 }
531}