Merge "Require READ_CALL_LOG permission to see phone numbers in phone state." into pi-dev
This commit is contained in:
@@ -1047,6 +1047,22 @@ class ContextImpl extends Context {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
|
||||
String[] receiverPermissions) {
|
||||
warnIfCallingFromSystemProcess();
|
||||
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
|
||||
try {
|
||||
intent.prepareToLeaveProcess(this);
|
||||
ActivityManager.getService().broadcastIntent(
|
||||
mMainThread.getApplicationThread(), intent, resolvedType, null,
|
||||
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
|
||||
null, false, false, user.getIdentifier());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
|
||||
warnIfCallingFromSystemProcess();
|
||||
|
||||
@@ -1974,6 +1974,33 @@ public abstract class Context {
|
||||
public abstract void sendBroadcastMultiplePermissions(Intent intent,
|
||||
String[] receiverPermissions);
|
||||
|
||||
/**
|
||||
* Broadcast the given intent to all interested BroadcastReceivers, allowing
|
||||
* an array of required permissions to be enforced. This call is asynchronous; it returns
|
||||
* immediately, and you will continue executing while the receivers are run. No results are
|
||||
* propagated from receivers and receivers can not abort the broadcast. If you want to allow
|
||||
* receivers to propagate results or abort the broadcast, you must send an ordered broadcast
|
||||
* using {@link #sendOrderedBroadcast(Intent, String)}.
|
||||
*
|
||||
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
|
||||
*
|
||||
* @param intent The Intent to broadcast; all receivers matching this
|
||||
* Intent will receive the broadcast.
|
||||
* @param user The user to send the broadcast to.
|
||||
* @param receiverPermissions Array of names of permissions that a receiver must hold
|
||||
* in order to receive your broadcast.
|
||||
* If null or empty, no permissions are required.
|
||||
*
|
||||
* @see android.content.BroadcastReceiver
|
||||
* @see #registerReceiver
|
||||
* @see #sendBroadcast(Intent)
|
||||
* @see #sendOrderedBroadcast(Intent, String)
|
||||
* @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
|
||||
* @hide
|
||||
*/
|
||||
public abstract void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
|
||||
String[] receiverPermissions);
|
||||
|
||||
/**
|
||||
* Broadcast the given intent to all interested BroadcastReceivers, allowing
|
||||
* an optional required permission to be enforced. This
|
||||
|
||||
@@ -455,6 +455,13 @@ public class ContextWrapper extends Context {
|
||||
mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
|
||||
String[] receiverPermissions) {
|
||||
mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@SystemApi
|
||||
@Override
|
||||
|
||||
@@ -117,10 +117,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
return (onSubscriptionsChangedListenerCallback != null);
|
||||
}
|
||||
|
||||
boolean canReadPhoneState() {
|
||||
boolean canReadCallLog() {
|
||||
try {
|
||||
return TelephonyPermissions.checkReadPhoneState(
|
||||
context, subId, callerPid, callerUid, callingPackage, "listen");
|
||||
return TelephonyPermissions.checkReadCallLog(
|
||||
context, subId, callerPid, callerUid, callingPackage);
|
||||
} catch (SecurityException e) {
|
||||
return false;
|
||||
}
|
||||
@@ -667,8 +667,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
}
|
||||
|
||||
private String getCallIncomingNumber(Record record, int phoneId) {
|
||||
// Hide the number if record's process can't currently read phone state.
|
||||
return record.canReadPhoneState() ? mCallIncomingNumber[phoneId] : "";
|
||||
// Only reveal the incoming number if the record has read call log permission.
|
||||
return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : "";
|
||||
}
|
||||
|
||||
private Record add(IBinder binder) {
|
||||
@@ -729,13 +729,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyCallState(int state, String incomingNumber) {
|
||||
public void notifyCallState(int state, String phoneNumber) {
|
||||
if (!checkNotifyPermission("notifyCallState()")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (VDBG) {
|
||||
log("notifyCallState: state=" + state + " incomingNumber=" + incomingNumber);
|
||||
log("notifyCallState: state=" + state + " phoneNumber=" + phoneNumber);
|
||||
}
|
||||
|
||||
synchronized (mRecords) {
|
||||
@@ -743,8 +743,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
|
||||
(r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
|
||||
try {
|
||||
String incomingNumberOrEmpty = r.canReadPhoneState() ? incomingNumber : "";
|
||||
r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
|
||||
// Ensure the listener has read call log permission; if they do not return
|
||||
// an empty phone number.
|
||||
String phoneNumberOrEmpty = r.canReadCallLog() ? phoneNumber : "";
|
||||
r.callback.onCallStateChanged(state, phoneNumberOrEmpty);
|
||||
} catch (RemoteException ex) {
|
||||
mRemoveList.add(r.binder);
|
||||
}
|
||||
@@ -755,7 +757,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
|
||||
// Called only by Telecomm to communicate call state across different phone accounts. So
|
||||
// there is no need to add a valid subId or slotId.
|
||||
broadcastCallStateChanged(state, incomingNumber,
|
||||
broadcastCallStateChanged(state, phoneNumber,
|
||||
SubscriptionManager.INVALID_PHONE_INDEX,
|
||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
||||
}
|
||||
@@ -1571,9 +1573,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
|
||||
intent.putExtra(PhoneConstants.STATE_KEY,
|
||||
PhoneConstantConversions.convertCallState(state).toString());
|
||||
if (!TextUtils.isEmpty(incomingNumber)) {
|
||||
intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
|
||||
}
|
||||
|
||||
// If a valid subId was specified, we should fire off a subId-specific state
|
||||
// change intent and include the subId.
|
||||
@@ -1589,13 +1588,20 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
// Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast.
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
|
||||
|
||||
Intent intentWithPhoneNumber = new Intent(intent);
|
||||
if (!TextUtils.isEmpty(incomingNumber)) {
|
||||
intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
|
||||
}
|
||||
// Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
|
||||
// that have the runtime one
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
|
||||
mContext.sendBroadcastAsUser(intentWithPhoneNumber, UserHandle.ALL,
|
||||
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
|
||||
android.Manifest.permission.READ_PHONE_STATE,
|
||||
AppOpsManager.OP_READ_PHONE_STATE);
|
||||
mContext.sendBroadcastAsUserMultiplePermissions(intentWithPhoneNumber, UserHandle.ALL,
|
||||
new String[] { android.Manifest.permission.READ_PHONE_STATE,
|
||||
android.Manifest.permission.READ_CALL_LOG});
|
||||
}
|
||||
|
||||
private void broadcastDataConnectionStateChanged(int state,
|
||||
|
||||
@@ -253,6 +253,12 @@ public class DpmMockContext extends MockContext {
|
||||
spiedContext.sendBroadcastMultiplePermissions(intent, receiverPermissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
|
||||
String[] receiverPermissions) {
|
||||
spiedContext.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
|
||||
spiedContext.sendBroadcast(intent, receiverPermission, options);
|
||||
|
||||
@@ -444,7 +444,7 @@ public class PhoneStateListener {
|
||||
* Callback invoked when device call state changes.
|
||||
* @param state call state
|
||||
* @param phoneNumber call phone number. If application does not have
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission or carrier
|
||||
* {@link android.Manifest.permission#READ_CALL_LOG READ_CALL_LOG} permission or carrier
|
||||
* privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
|
||||
* passed as an argument.
|
||||
*
|
||||
|
||||
@@ -334,10 +334,12 @@ public class TelephonyManager {
|
||||
*
|
||||
* <p>
|
||||
* The {@link #EXTRA_STATE} extra indicates the new call state.
|
||||
* If the new state is RINGING, a second extra
|
||||
* {@link #EXTRA_INCOMING_NUMBER} provides the incoming phone number as
|
||||
* a String.
|
||||
*
|
||||
* If a receiving app has {@link android.Manifest.permission#READ_CALL_LOG} permission, a second
|
||||
* extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outoing calls
|
||||
* as a String. Note: If the receiving app has
|
||||
* {@link android.Manifest.permission#READ_CALL_LOG} and
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE} permission, it will receive the
|
||||
* broadcast twice; one with the phone number and another without it.
|
||||
* <p class="note">
|
||||
* This was a {@link android.content.Context#sendStickyBroadcast sticky}
|
||||
* broadcast in version 1.0, but it is no longer sticky.
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -75,7 +78,7 @@ public final class TelephonyPermissions {
|
||||
/**
|
||||
* Check whether the app with the given pid/uid can read phone state.
|
||||
*
|
||||
* <p>This method behaves in one of the following ways:
|
||||
* <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
|
||||
* READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
|
||||
@@ -131,6 +134,40 @@ public final class TelephonyPermissions {
|
||||
AppOpsManager.MODE_ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* to it, {@code false} otherwise.
|
||||
*/
|
||||
public static boolean checkReadCallLog(
|
||||
Context context, int subId, int pid, int uid, String callingPackage) {
|
||||
return checkReadCallLog(
|
||||
context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static boolean checkReadCallLog(
|
||||
Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
|
||||
String callingPackage) {
|
||||
|
||||
if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
|
||||
!= PERMISSION_GRANTED) {
|
||||
// If we don't have the runtime permission, but do have carrier privileges, that
|
||||
// suffices for being able to see the call phone numbers.
|
||||
if (SubscriptionManager.isValidSubscriptionId(subId)) {
|
||||
enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been
|
||||
// revoked.
|
||||
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
|
||||
return appOps.noteOp(AppOpsManager.OP_READ_CALL_LOG, uid, callingPackage) ==
|
||||
AppOpsManager.MODE_ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the caller can read phone numbers.
|
||||
*
|
||||
@@ -204,7 +241,7 @@ public final class TelephonyPermissions {
|
||||
public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
|
||||
Context context, int subId, String message) {
|
||||
if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) ==
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -363,6 +363,13 @@ public class MockContext extends Context {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
|
||||
String[] receiverPermissions) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@SystemApi
|
||||
@Override
|
||||
|
||||
@@ -174,6 +174,12 @@ public class BroadcastInterceptingContext extends ContextWrapper {
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
|
||||
String[] receiverPermissions) {
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
|
||||
sendBroadcast(intent);
|
||||
|
||||
Reference in New Issue
Block a user