1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
4 * Not a Contribution.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19package com.android.internal.telephony;
20
21import android.app.AppOpsManager;
22import android.content.Context;
23import android.content.pm.PackageManager;
24import android.os.Binder;
25import android.os.RemoteException;
26import android.os.ServiceManager;
27import android.telephony.PhoneNumberUtils;
28import android.telephony.SubscriptionManager;
29import android.telephony.Rlog;
30
31import com.android.internal.telephony.uicc.IsimRecords;
32import com.android.internal.telephony.uicc.UiccCard;
33import com.android.internal.telephony.uicc.UiccCardApplication;
34
35import static android.Manifest.permission.CALL_PRIVILEGED;
36import static android.Manifest.permission.READ_PHONE_NUMBERS;
37import static android.Manifest.permission.READ_PHONE_STATE;
38import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
39import static android.Manifest.permission.READ_SMS;
40import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
41
42public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
43    private static final String TAG = "PhoneSubInfoController";
44    private static final boolean DBG = true;
45    private static final boolean VDBG = false; // STOPSHIP if true
46
47    private final Phone[] mPhone;
48    private final Context mContext;
49    private final AppOpsManager mAppOps;
50
51    public PhoneSubInfoController(Context context, Phone[] phone) {
52        mPhone = phone;
53        if (ServiceManager.getService("iphonesubinfo") == null) {
54            ServiceManager.addService("iphonesubinfo", this);
55        }
56        mContext = context;
57        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
58    }
59
60    public String getDeviceId(String callingPackage) {
61        return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()),
62                callingPackage);
63    }
64
65    public String getDeviceIdForPhone(int phoneId, String callingPackage) {
66        if (!checkReadPhoneState(callingPackage, "getDeviceId")) {
67            return null;
68        }
69        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
70            phoneId = 0;
71        }
72        final Phone phone = mPhone[phoneId];
73        if (phone != null) {
74            return phone.getDeviceId();
75        } else {
76            loge("getDeviceIdForPhone phone " + phoneId + " is null");
77            return null;
78        }
79    }
80
81    public String getNaiForSubscriber(int subId, String callingPackage) {
82        Phone phone = getPhone(subId);
83        if (phone != null) {
84            if (!checkReadPhoneState(callingPackage, "getNai")) {
85                return null;
86            }
87            return phone.getNai();
88        } else {
89            loge("getNai phone is null for Subscription:" + subId);
90            return null;
91        }
92    }
93
94    public String getImeiForSubscriber(int subId, String callingPackage) {
95        Phone phone = getPhone(subId);
96        if (phone != null) {
97            if (!checkReadPhoneState(callingPackage, "getImei")) {
98                return null;
99            }
100            return phone.getImei();
101        } else {
102            loge("getDeviceId phone is null for Subscription:" + subId);
103            return null;
104        }
105    }
106
107    public String getDeviceSvn(String callingPackage) {
108        return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage);
109    }
110
111    public String getDeviceSvnUsingSubId(int subId, String callingPackage) {
112        Phone phone = getPhone(subId);
113        if (phone != null) {
114            if (!checkReadPhoneState(callingPackage, "getDeviceSvn")) {
115                return null;
116            }
117            return phone.getDeviceSvn();
118        } else {
119            loge("getDeviceSvn phone is null");
120            return null;
121        }
122    }
123
124    public String getSubscriberId(String callingPackage) {
125        return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage);
126    }
127
128    public String getSubscriberIdForSubscriber(int subId, String callingPackage) {
129        Phone phone = getPhone(subId);
130        if (phone != null) {
131            if (!checkReadPhoneState(callingPackage, "getSubscriberId")) {
132                return null;
133            }
134            return phone.getSubscriberId();
135        } else {
136            loge("getSubscriberId phone is null for Subscription:" + subId);
137            return null;
138        }
139    }
140
141    /**
142     * Retrieves the serial number of the ICC, if applicable.
143     */
144    public String getIccSerialNumber(String callingPackage) {
145        return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage);
146    }
147
148    public String getIccSerialNumberForSubscriber(int subId, String callingPackage) {
149        Phone phone = getPhone(subId);
150        if (phone != null) {
151            if (!checkReadPhoneState(callingPackage, "getIccSerialNumber")) {
152                return null;
153            }
154            return phone.getIccSerialNumber();
155        } else {
156            loge("getIccSerialNumber phone is null for Subscription:" + subId);
157            return null;
158        }
159    }
160
161    public String getLine1Number(String callingPackage) {
162        return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage);
163    }
164
165    public String getLine1NumberForSubscriber(int subId, String callingPackage) {
166        Phone phone = getPhone(subId);
167        if (phone != null) {
168            // This is open to apps with WRITE_SMS.
169            if (!checkReadPhoneNumber(callingPackage, "getLine1Number")) {
170                return null;
171            }
172            return phone.getLine1Number();
173        } else {
174            loge("getLine1Number phone is null for Subscription:" + subId);
175            return null;
176        }
177    }
178
179    public String getLine1AlphaTag(String callingPackage) {
180        return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
181    }
182
183    public String getLine1AlphaTagForSubscriber(int subId, String callingPackage) {
184        Phone phone = getPhone(subId);
185        if (phone != null) {
186            if (!checkReadPhoneState(callingPackage, "getLine1AlphaTag")) {
187                return null;
188            }
189            return phone.getLine1AlphaTag();
190        } else {
191            loge("getLine1AlphaTag phone is null for Subscription:" + subId);
192            return null;
193        }
194    }
195
196    public String getMsisdn(String callingPackage) {
197        return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage);
198    }
199
200    public String getMsisdnForSubscriber(int subId, String callingPackage) {
201        Phone phone = getPhone(subId);
202        if (phone != null) {
203            if (!checkReadPhoneState(callingPackage, "getMsisdn")) {
204                return null;
205            }
206            return phone.getMsisdn();
207        } else {
208            loge("getMsisdn phone is null for Subscription:" + subId);
209            return null;
210        }
211    }
212
213    public String getVoiceMailNumber(String callingPackage) {
214        return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage);
215    }
216
217    public String getVoiceMailNumberForSubscriber(int subId, String callingPackage) {
218        Phone phone = getPhone(subId);
219        if (phone != null) {
220            if (!checkReadPhoneState(callingPackage, "getVoiceMailNumber")) {
221                return null;
222            }
223            String number = PhoneNumberUtils.extractNetworkPortion(phone.getVoiceMailNumber());
224            if (VDBG) log("VM: getVoiceMailNUmber: " + number);
225            return number;
226        } else {
227            loge("getVoiceMailNumber phone is null for Subscription:" + subId);
228            return null;
229        }
230    }
231
232    // TODO: change getCompleteVoiceMailNumber() to require READ_PRIVILEGED_PHONE_STATE
233    public String getCompleteVoiceMailNumber() {
234        return getCompleteVoiceMailNumberForSubscriber(getDefaultSubscription());
235    }
236
237    public String getCompleteVoiceMailNumberForSubscriber(int subId) {
238        Phone phone = getPhone(subId);
239        if (phone != null) {
240            mContext.enforceCallingOrSelfPermission(CALL_PRIVILEGED, "Requires CALL_PRIVILEGED");
241            String number = phone.getVoiceMailNumber();
242            if (VDBG) log("VM: getCompleteVoiceMailNUmber: " + number);
243            return number;
244        } else {
245            loge("getCompleteVoiceMailNumber phone is null for Subscription:" + subId);
246            return null;
247        }
248    }
249
250    public String getVoiceMailAlphaTag(String callingPackage) {
251        return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
252    }
253
254    public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage) {
255        Phone phone = getPhone(subId);
256        if (phone != null) {
257            if (!checkReadPhoneState(callingPackage, "getVoiceMailAlphaTag")) {
258                return null;
259            }
260            return phone.getVoiceMailAlphaTag();
261        } else {
262            loge("getVoiceMailAlphaTag phone is null for Subscription:" + subId);
263            return null;
264        }
265    }
266
267    /**
268     * get Phone object based on subId.
269     **/
270    private Phone getPhone(int subId) {
271        int phoneId = SubscriptionManager.getPhoneId(subId);
272        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
273            phoneId = 0;
274        }
275        return mPhone[phoneId];
276    }
277
278    /**
279     * Make sure caller has either read privileged phone permission or carrier privilege.
280     *
281     * @throws SecurityException if the caller does not have the required permission/privilege
282     */
283    private void enforcePrivilegedPermissionOrCarrierPrivilege(Phone phone) {
284        int permissionResult = mContext.checkCallingOrSelfPermission(
285                READ_PRIVILEGED_PHONE_STATE);
286        if (permissionResult == PackageManager.PERMISSION_GRANTED) {
287            return;
288        }
289        log("No read privileged phone permission, check carrier privilege next.");
290        UiccCard uiccCard = phone.getUiccCard();
291        if (uiccCard == null) {
292            throw new SecurityException("No Carrier Privilege: No UICC");
293        }
294        if (uiccCard.getCarrierPrivilegeStatusForCurrentTransaction(
295                mContext.getPackageManager()) != CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
296            throw new SecurityException("No Carrier Privilege.");
297        }
298    }
299
300    private int getDefaultSubscription() {
301        return  PhoneFactory.getDefaultSubscription();
302    }
303
304
305    public String getIsimImpi() {
306        Phone phone = getPhone(getDefaultSubscription());
307        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
308                "Requires READ_PRIVILEGED_PHONE_STATE");
309        IsimRecords isim = phone.getIsimRecords();
310        if (isim != null) {
311            return isim.getIsimImpi();
312        } else {
313            return null;
314        }
315    }
316
317    public String getIsimDomain() {
318        Phone phone = getPhone(getDefaultSubscription());
319        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
320                "Requires READ_PRIVILEGED_PHONE_STATE");
321        IsimRecords isim = phone.getIsimRecords();
322        if (isim != null) {
323            return isim.getIsimDomain();
324        } else {
325            return null;
326        }
327    }
328
329    public String[] getIsimImpu() {
330        Phone phone = getPhone(getDefaultSubscription());
331        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
332                "Requires READ_PRIVILEGED_PHONE_STATE");
333        IsimRecords isim = phone.getIsimRecords();
334        if (isim != null) {
335            return isim.getIsimImpu();
336        } else {
337            return null;
338        }
339    }
340
341    public String getIsimIst() throws RemoteException {
342        Phone phone = getPhone(getDefaultSubscription());
343        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
344                "Requires READ_PRIVILEGED_PHONE_STATE");
345        IsimRecords isim = phone.getIsimRecords();
346        if (isim != null) {
347            return isim.getIsimIst();
348        } else {
349            return null;
350        }
351    }
352
353    public String[] getIsimPcscf() throws RemoteException {
354        Phone phone = getPhone(getDefaultSubscription());
355        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
356                "Requires READ_PRIVILEGED_PHONE_STATE");
357        IsimRecords isim = phone.getIsimRecords();
358        if (isim != null) {
359            return isim.getIsimPcscf();
360        } else {
361            return null;
362        }
363    }
364
365    public String getIsimChallengeResponse(String nonce) throws RemoteException {
366        Phone phone = getPhone(getDefaultSubscription());
367        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
368                "Requires READ_PRIVILEGED_PHONE_STATE");
369        IsimRecords isim = phone.getIsimRecords();
370        if (isim != null) {
371            return isim.getIsimChallengeResponse(nonce);
372        } else {
373            return null;
374        }
375    }
376
377    public String getIccSimChallengeResponse(int subId, int appType, int authType, String data)
378            throws RemoteException {
379        Phone phone = getPhone(subId);
380        enforcePrivilegedPermissionOrCarrierPrivilege(phone);
381        UiccCard uiccCard = phone.getUiccCard();
382        if (uiccCard == null) {
383            loge("getIccSimChallengeResponse() UiccCard is null");
384            return null;
385        }
386
387        UiccCardApplication uiccApp = uiccCard.getApplicationByType(appType);
388        if (uiccApp == null) {
389            loge("getIccSimChallengeResponse() no app with specified type -- " +
390                    appType);
391            return null;
392        } else {
393            loge("getIccSimChallengeResponse() found app " + uiccApp.getAid()
394                    + " specified type -- " + appType);
395        }
396
397        if(authType != UiccCardApplication.AUTH_CONTEXT_EAP_SIM &&
398                authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA) {
399            loge("getIccSimChallengeResponse() unsupported authType: " + authType);
400            return null;
401        }
402
403        return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data);
404    }
405
406    public String getGroupIdLevel1(String callingPackage) {
407        return getGroupIdLevel1ForSubscriber(getDefaultSubscription(), callingPackage);
408    }
409
410    public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage) {
411        Phone phone = getPhone(subId);
412        if (phone != null) {
413            if (!checkReadPhoneState(callingPackage, "getGroupIdLevel1")) {
414                return null;
415            }
416            return phone.getGroupIdLevel1();
417        } else {
418            loge("getGroupIdLevel1 phone is null for Subscription:" + subId);
419            return null;
420        }
421    }
422
423    private boolean checkReadPhoneState(String callingPackage, String message) {
424        try {
425            mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message);
426
427            // SKIP checking run-time OP_READ_PHONE_STATE since self or using PRIVILEGED
428            return true;
429        } catch (SecurityException e) {
430            mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, message);
431        }
432
433        return mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
434                callingPackage) == AppOpsManager.MODE_ALLOWED;
435    }
436
437    /**
438     * Besides READ_PHONE_STATE, READ_PHONE_NUMBERS, WRITE_SMS and READ_SMS also allow apps to get
439     * phone numbers.
440     */
441    private boolean checkReadPhoneNumber(String callingPackage, String message) {
442        // Default SMS app can always read it.
443        if (mAppOps.noteOp(AppOpsManager.OP_WRITE_SMS,
444                Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED) {
445            return true;
446        }
447        try {
448            return checkReadPhoneState(callingPackage, message);
449        } catch (SecurityException readPhoneStateSecurityException) {
450        }
451        try {
452            // Can be read with READ_SMS too.
453            mContext.enforceCallingOrSelfPermission(READ_SMS, message);
454            int opCode = mAppOps.permissionToOpCode(READ_SMS);
455            if (opCode != AppOpsManager.OP_NONE) {
456                return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
457                        == AppOpsManager.MODE_ALLOWED;
458            } else {
459                return true;
460            }
461        } catch (SecurityException readSmsSecurityException) {
462        }
463        try {
464            // Can be read with READ_PHONE_NUMBERS too.
465            mContext.enforceCallingOrSelfPermission(READ_PHONE_NUMBERS, message);
466            int opCode = mAppOps.permissionToOpCode(READ_PHONE_NUMBERS);
467            if (opCode != AppOpsManager.OP_NONE) {
468                return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
469                        == AppOpsManager.MODE_ALLOWED;
470            } else {
471                return true;
472            }
473        } catch (SecurityException readPhoneNumberSecurityException) {
474        }
475        // Throw exception with message including READ_PHONE_STATE, READ_SMS, and READ_PHONE_NUMBERS
476        // permissions
477        throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() +
478                " nor current process has " + READ_PHONE_STATE + ", " +
479                READ_SMS + ", or " + READ_PHONE_STATE + ".");
480    }
481
482    private void log(String s) {
483        Rlog.d(TAG, s);
484    }
485
486    private void loge(String s) {
487        Rlog.e(TAG, s);
488    }
489}
490