Protect Device Identifiers behind priv permission and DO/PO checks

Bug: 110099294
Test: cts-tradefed run cts -m CtsDevicePolicyManagerTestCases \
      -t com.android.cts.devicepolicy.DeviceOwnerTest.testDeviceOwnerCanGetDeviceIdentifiers
Test: cts-tradefed run cts -m CtsDevicePolicyManagerTestCases \
      -t com.android.cts.devicepolicy.ManagedProfileTest#testGetDeviceIdentifiers
Test: cts-tradefed run cts -m CtsTelephonyTestCases -t android.telephony.cts.TelephonyManagerTest
Test: cts-tradefed run cts -m CtsPermissionTestCases -t android.permission.cts.TelephonyManagerPermissionTest

Change-Id: I3c82c53ec89cd17b34a61166ccc9e9747388efac
This commit is contained in:
Michael Groover
2018-10-01 16:14:50 -07:00
parent 42f4e79d7e
commit 6d20d75e9e
11 changed files with 333 additions and 50 deletions

View File

@@ -5702,6 +5702,37 @@ public class DevicePolicyManager {
return null;
}
/**
* Returns whether the specified package can read the device identifiers.
*
* @param packageName The package name of the app to check for device identifier access.
* @return whether the package can read the device identifiers.
*
* @hide
*/
public boolean checkDeviceIdentifierAccess(String packageName) {
return checkDeviceIdentifierAccessAsUser(packageName, myUserId());
}
/**
* @hide
*/
@RequiresPermission(value = android.Manifest.permission.MANAGE_USERS, conditional = true)
public boolean checkDeviceIdentifierAccessAsUser(String packageName, int userId) {
throwIfParentInstance("checkDeviceIdentifierAccessAsUser");
if (packageName == null) {
return false;
}
if (mService != null) {
try {
return mService.checkDeviceIdentifierAccess(packageName, userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
return false;
}
/**
* Called by a profile owner or device owner to set a default activity that the system selects
* to handle intents that match the given {@link IntentFilter}. This activity will remain the

View File

@@ -153,6 +153,8 @@ interface IDevicePolicyManager {
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
boolean checkDeviceIdentifierAccess(in String packageName, int userHandle);
void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
CharSequence getDeviceOwnerLockScreenInfo();

View File

@@ -18,8 +18,10 @@ package android.os;
import android.Manifest;
import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.Application;
import android.content.Context;
import android.text.TextUtils;
@@ -127,14 +129,21 @@ public class Build {
* <a href="/training/articles/security-key-attestation.html">key attestation</a> to obtain
* proof of the device's original identifiers.
*
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
* device or profile owner. Profile owner access is deprecated and will be removed in a future
* release.
*
* @return The serial number if specified.
*/
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@SuppressAutoDoc // No support for device / profile owner.
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public static String getSerial() {
IDeviceIdentifiersPolicyService service = IDeviceIdentifiersPolicyService.Stub
.asInterface(ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE));
try {
return service.getSerial();
Application application = ActivityThread.currentApplication();
String callingPackage = application != null ? application.getPackageName() : null;
return service.getSerialForPackage(callingPackage);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}

View File

@@ -21,4 +21,5 @@ package android.os;
*/
interface IDeviceIdentifiersPolicyService {
String getSerial();
String getSerialForPackage(in String callingPackage);
}

View File

@@ -16,6 +16,7 @@
package com.android.bandwidthtest;
import android.app.UiAutomation;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
@@ -74,7 +75,13 @@ public class BandwidthTest extends InstrumentationTestCase {
Log.v(LOG_TAG, "Initialized mConnectionUtil");
mUid = Process.myUid();
mTManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
mDeviceId = mTManager.getDeviceId();
final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
uiAutomation.adoptShellPermissionIdentity();
mDeviceId = mTManager.getDeviceId();
} finally {
uiAutomation.dropShellPermissionIdentity();
}
}
@Override

View File

@@ -322,6 +322,7 @@ applications that come with the platform
<permission name="android.permission.PACKAGE_USAGE_STATS" />
<permission name="android.permission.READ_FRAME_BUFFER"/>
<permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.REAL_GET_TASKS"/>
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
<permission name="android.permission.REGISTER_CONNECTION_MANAGER"/>

View File

@@ -16,18 +16,15 @@
package com.android.server.os;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.IDeviceIdentifiersPolicyService;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import com.android.internal.telephony.TelephonyPermissions;
import com.android.server.SystemService;
/**
@@ -54,15 +51,22 @@ public final class DeviceIdentifiersPolicyService extends SystemService {
@Override
public @Nullable String getSerial() throws RemoteException {
if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
&& mContext.checkCallingOrSelfPermission(
Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED
&& mContext.checkCallingOrSelfPermission(
Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("getSerial requires READ_PHONE_STATE"
+ " or READ_PRIVILEGED_PHONE_STATE permission");
// Since this invocation is on the server side a null value is used for the
// callingPackage as the server's package name (typically android) should not be used
// for any device / profile owner checks. The majority of requests for the serial number
// should use the getSerialForPackage method with the calling package specified.
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
/* callingPackage */ null, "getSerial")) {
return null;
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}
@Override
public @Nullable String getSerialForPackage(String callingPackage) throws RemoteException {
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
callingPackage, "getSerial")) {
return null;
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}

View File

@@ -66,4 +66,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public long forceSecurityLogs() {
return 0;
}
@Override
public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
return false;
}
}

View File

@@ -7861,6 +7861,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return getApplicationLabel(profileOwner.getPackageName(), userHandle);
}
@Override
public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
// Allow access to the device owner.
ComponentName deviceOwner = getDeviceOwnerComponent(true);
if (deviceOwner != null && deviceOwner.getPackageName().equals(packageName)) {
return true;
}
// Allow access to the profile owner for the specified user.
ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
if (profileOwner != null && profileOwner.getPackageName().equals(packageName)) {
return true;
}
return false;
}
/**
* Canonical name for a given package.
*/

View File

@@ -1268,15 +1268,18 @@ public class TelephonyManager {
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
* device or profile owner. The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*
* @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
* MEID for CDMA.
*/
@Deprecated
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@SuppressAutoDoc // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getDeviceId() {
try {
ITelephony telephony = getITelephony();
@@ -1294,8 +1297,11 @@ public class TelephonyManager {
* Returns the unique device ID of a subscription, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
* device or profile owner. The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*
* @param slotIndex of which deviceID is returned
*
@@ -1303,8 +1309,8 @@ public class TelephonyManager {
* MEID for CDMA.
*/
@Deprecated
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@SuppressAutoDoc // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
try {
@@ -1323,11 +1329,14 @@ public class TelephonyManager {
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
* device or profile owner. The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@SuppressAutoDoc // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getImei() {
return getImei(getSlotIndex());
}
@@ -1336,13 +1345,16 @@ public class TelephonyManager {
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
* device or profile owner. The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*
* @param slotIndex of which IMEI is returned
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@SuppressAutoDoc // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getImei(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -1386,11 +1398,14 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
* device or profile owner. The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@SuppressAutoDoc // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getMeid() {
return getMeid(getSlotIndex());
}
@@ -1398,13 +1413,16 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
* device or profile owner. The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*
* @param slotIndex of which MEID is returned
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@SuppressAutoDoc // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getMeid(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -2888,11 +2906,15 @@ public class TelephonyManager {
* Returns the serial number of the SIM, if applicable. Return null if it is
* unavailable.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
* profile owner, or that the calling app has carrier privileges (see {@link
* #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getSimSerialNumber() {
return getSimSerialNumber(getSubId());
}
@@ -2900,11 +2922,18 @@ public class TelephonyManager {
/**
* Returns the serial number for the given subscription, if applicable. Return null if it is
* unavailable.
* <p>
*
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
* profile owner, or that the calling app has carrier privileges (see {@link
* #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*
* @param subId for which Sim Serial number is returned
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage
public String getSimSerialNumber(int subId) {
try {
@@ -3039,11 +3068,15 @@ public class TelephonyManager {
* Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
* Return null if it is unavailable.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
* profile owner, or that the calling app has carrier privileges (see {@link
* #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getSubscriberId() {
return getSubscriberId(getSubId());
}
@@ -3053,10 +3086,17 @@ public class TelephonyManager {
* for a subscription.
* Return null if it is unavailable.
*
* <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
* profile owner, or that the calling app has carrier privileges (see {@link
* #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
* device; for more details see <a href="https://developer.android.com/work/managed-profiles">
* Work profiles</a>. Profile owner access is deprecated and will be removed in a future
* release.
*
* @param subId whose subscriber id is returned
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage
public String getSubscriberId(int subId) {
try {

View File

@@ -19,11 +19,16 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -134,6 +139,169 @@ public final class TelephonyPermissions {
AppOpsManager.MODE_ALLOWED;
}
/**
* Check whether the caller (or self, if not processing an IPC) can read device identifiers.
*
* <p>This method behaves in one of the following ways:
* <ul>
* <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the
* calling package passes a DevicePolicyManager Device Owner / Profile Owner device
* identifier access check,
* <li>throw SecurityException: if the caller does not meet any of the requirements and is
* targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
* the calling function should return dummy data.
* </ul>
*/
public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
String callingPackage, String message) {
return checkCallingOrSelfReadDeviceIdentifiers(context,
SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message);
}
/**
* Check whether the caller (or self, if not processing an IPC) can read device identifiers.
*
* <p>This method behaves in one of the following ways:
* <ul>
* <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the
* calling package passes a DevicePolicyManager Device Owner / Profile Owner device
* identifier access check,
* <li>throw SecurityException: if the caller does not meet any of the requirements and is
* targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
* or carrier privileges.
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission or carrier privileges. In this case the caller would expect to have access
* to the device identifiers so false is returned instead of throwing a SecurityException
* to indicate the calling function should return dummy data.
* </ul>
*/
public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
String callingPackage, String message) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
// if the device identifier check completes successfully then grant access.
if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
return true;
}
// else the calling package is not authorized to access the device identifiers; call
// a central method to report the failure based on the target SDK and if the calling package
// has the READ_PHONE_STATE permission or carrier privileges that were previously required
// to access the identifiers.
return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
message);
}
/**
* Check whether the caller (or self, if not processing an IPC) can read subscriber identifiers.
*
* <p>This method behaves in one of the following ways:
* <ul>
* <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
* package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
* access check, or the calling package has carrier privleges.
* <li>throw SecurityException: if the caller does not meet any of the requirements and is
* targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
* the calling function should return dummy data.
* </ul>
*/
public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
String callingPackage, String message) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
// if the device identifiers can be read then grant access to the subscriber identifiers
if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
return true;
}
// If the calling package has carrier privileges then allow access to the subscriber
// identifiers.
if (SubscriptionManager.isValidSubscriptionId(subId) && getCarrierPrivilegeStatus(
TELEPHONY_SUPPLIER, subId, uid)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
return true;
}
return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
message);
}
/**
* Checks whether the app with the given pid/uid can read device identifiers.
*
* @returns true if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the calling
* package passes a DevicePolicyManager Device Owner / Profile Owner device identifier access
* check.
*/
private static boolean checkReadDeviceIdentifiers(Context context, int pid, int uid,
String callingPackage) {
// Allow system and root access to the device identifiers.
final int appId = UserHandle.getAppId(uid);
if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
return true;
}
// Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
if (context.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
uid) == PackageManager.PERMISSION_GRANTED) {
return true;
}
// if the calling package is null then return now as there's no way to perform the
// DevicePolicyManager device / profile owner checks.
if (callingPackage == null) {
return false;
}
// Allow access to a device / profile owner app.
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
if (devicePolicyManager != null && devicePolicyManager.checkDeviceIdentifierAccessAsUser(
callingPackage, Binder.getCallingUserHandle().getIdentifier())) {
return true;
}
return false;
}
/**
* Reports a failure when the app with the given pid/uid cannot access the requested identifier.
*
* @returns false if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission or carrier privileges.
* @throws SecurityException if the caller does not meet any of the requirements for the
* requested identifier and is targeting Q or is targeting pre-Q
* and does not have the READ_PHONE_STATE permission or carrier
* privileges.
*/
private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
int uid, String callingPackage, String message) {
if (callingPackage != null) {
try {
// if the target SDK is pre-Q then check if the calling package would have
// previously had access to device identifiers.
ApplicationInfo callingPackageInfo = context.getPackageManager().getApplicationInfo(
callingPackage, 0);
if (callingPackageInfo != null
&& callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
if (context.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid,
uid) == PackageManager.PERMISSION_GRANTED) {
return false;
}
if (SubscriptionManager.isValidSubscriptionId(subId)
&& getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
return false;
}
}
} catch (PackageManager.NameNotFoundException e) {
// If the application info for the calling package could not be found then default
// to throwing the SecurityException.
}
}
throw new SecurityException(message + ": The user " + uid + " does not have the "
+ "READ_PRIVILEGED_PHONE_STATE permission to access the device identifiers");
}
/**
* Check whether the app with the given pid/uid can read the call log.
* @return {@code true} if the specified app has the read call log permission and AppOpp granted