am 6fe87a56: am 68ffcf88: Merge "Teach receivers, activities, providers, and services app ops." into mnc-dev
* commit '6fe87a565be345c9455f610bbf26d5eaee593683':
Teach receivers, activities, providers, and services app ops.
diff --git a/api/current.txt b/api/current.txt
index df66811..3304317 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3855,6 +3855,8 @@
method public void finishOp(java.lang.String, int, java.lang.String);
method public int noteOp(java.lang.String, int, java.lang.String);
method public int noteOpNoThrow(java.lang.String, int, java.lang.String);
+ method public int noteProxyOp(java.lang.String, java.lang.String);
+ method public int noteProxyOpNoThrow(java.lang.String, java.lang.String);
method public static java.lang.String permissionToOp(java.lang.String);
method public int startOp(java.lang.String, int, java.lang.String);
method public int startOpNoThrow(java.lang.String, int, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index f6301e8..e3f003c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3964,6 +3964,8 @@
method public void finishOp(java.lang.String, int, java.lang.String);
method public int noteOp(java.lang.String, int, java.lang.String);
method public int noteOpNoThrow(java.lang.String, int, java.lang.String);
+ method public int noteProxyOp(java.lang.String, java.lang.String);
+ method public int noteProxyOpNoThrow(java.lang.String, java.lang.String);
method public static java.lang.String permissionToOp(java.lang.String);
method public int startOp(java.lang.String, int, java.lang.String);
method public int startOpNoThrow(java.lang.String, int, java.lang.String);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 2ed4b51..8797b13 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -770,7 +770,7 @@
return;
}
System.out.println("Starting service: " + intent);
- ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId);
+ ComponentName cn = mAm.startService(null, intent, intent.getType(), null, mUserId);
if (cn == null) {
System.err.println("Error: Not found; no service started.");
} else if (cn.getPackageName().equals("!")) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 2bb4e76..cc93ac9 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -921,8 +921,9 @@
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
+ String callingPackage = data.readString();
int userId = data.readInt();
- ComponentName cn = startService(app, service, resolvedType, userId);
+ ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);
reply.writeNoException();
ComponentName.writeToParcel(cn, reply);
return true;
@@ -976,9 +977,11 @@
String resolvedType = data.readString();
b = data.readStrongBinder();
int fl = data.readInt();
+ String callingPackage = data.readString();
int userId = data.readInt();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
- int res = bindService(app, token, service, resolvedType, conn, fl, userId);
+ int res = bindService(app, token, service, resolvedType, conn, fl,
+ callingPackage, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -1568,7 +1571,8 @@
data.enforceInterface(IActivityManager.descriptor);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
- IBinder binder = peekService(service, resolvedType);
+ String callingPackage = data.readString();
+ IBinder binder = peekService(service, resolvedType, callingPackage);
reply.writeNoException();
reply.writeStrongBinder(binder);
return true;
@@ -3638,7 +3642,7 @@
}
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, int userId) throws RemoteException
+ String resolvedType, String callingPackage, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -3646,6 +3650,7 @@
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
+ data.writeString(callingPackage);
data.writeInt(userId);
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
@@ -3708,7 +3713,7 @@
}
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
- int flags, int userId) throws RemoteException {
+ int flags, String callingPackage, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3718,6 +3723,7 @@
data.writeString(resolvedType);
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
+ data.writeString(callingPackage);
data.writeInt(userId);
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
@@ -3783,12 +3789,14 @@
reply.recycle();
}
- public IBinder peekService(Intent service, String resolvedType) throws RemoteException {
+ public IBinder peekService(Intent service, String resolvedType, String callingPackage)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
+ data.writeString(callingPackage);
mRemote.transact(PEEK_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
IBinder binder = reply.readStrongBinder();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 9faadd3..bf3bfae 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1082,13 +1082,18 @@
private final long mTime;
private final long mRejectTime;
private final int mDuration;
+ private final int mProxyUid;
+ private final String mProxyPackageName;
- public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
+ public OpEntry(int op, int mode, long time, long rejectTime, int duration,
+ int proxyUid, String proxyPackage) {
mOp = op;
mMode = mode;
mTime = time;
mRejectTime = rejectTime;
mDuration = duration;
+ mProxyUid = proxyUid;
+ mProxyPackageName = proxyPackage;
}
public int getOp() {
@@ -1115,6 +1120,14 @@
return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
}
+ public int getProxyUid() {
+ return mProxyUid;
+ }
+
+ public String getProxyPackageName() {
+ return mProxyPackageName;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1127,6 +1140,8 @@
dest.writeLong(mTime);
dest.writeLong(mRejectTime);
dest.writeInt(mDuration);
+ dest.writeInt(mProxyUid);
+ dest.writeString(mProxyPackageName);
}
OpEntry(Parcel source) {
@@ -1135,6 +1150,8 @@
mTime = source.readLong();
mRejectTime = source.readLong();
mDuration = source.readInt();
+ mProxyUid = source.readInt();
+ mProxyPackageName = source.readString();
}
public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
@@ -1379,6 +1396,33 @@
}
/**
+ * Make note of an application performing an operation on behalf of another
+ * application when handling an IPC. Note that you must pass the package name
+ * of the application that is being proxied while its UID will be inferred from
+ * the IPC state; this function will verify that the calling uid and proxied
+ * package name match, and if not, return {@link #MODE_IGNORED}. If this call
+ * succeeds, the last execution time of the operation for the proxied app and
+ * your app will be updated to the current time.
+ * @param op The operation to note. One of the OPSTR_* constants.
+ * @param proxiedPackageName The name of the application calling into the proxy application.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
+ */
+ public int noteProxyOp(String op, String proxiedPackageName) {
+ return noteProxyOp(strOpToOp(op), proxiedPackageName);
+ }
+
+ /**
+ * Like {@link #noteProxyOp(String, String)} but instead
+ * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}.
+ */
+ public int noteProxyOpNoThrow(String op, String proxiedPackageName) {
+ return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName);
+ }
+
+ /**
* Report that an application has started executing a long-running operation. Note that you
* must pass in both the uid and name of the application to be checked; this function will
* verify that these two match, and if not, return {@link #MODE_IGNORED}. If this call
@@ -1455,7 +1499,7 @@
return mService.checkOperation(op, uid, packageName);
} catch (RemoteException e) {
}
- return MODE_IGNORED;
+ return MODE_ERRORED;
}
/**
@@ -1501,7 +1545,7 @@
return mService.checkAudioOperation(op, stream, uid, packageName);
} catch (RemoteException e) {
}
- return MODE_IGNORED;
+ return MODE_ERRORED;
}
/**
@@ -1532,6 +1576,49 @@
}
/**
+ * Make note of an application performing an operation on behalf of another
+ * application when handling an IPC. Note that you must pass the package name
+ * of the application that is being proxied while its UID will be inferred from
+ * the IPC state; this function will verify that the calling uid and proxied
+ * package name match, and if not, return {@link #MODE_IGNORED}. If this call
+ * succeeds, the last execution time of the operation for the proxied app and
+ * your app will be updated to the current time.
+ * @param op The operation to note. One of the OPSTR_* constants.
+ * @param proxiedPackageName The name of the application calling into the proxy application.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the proxy or proxied app has been configured to
+ * crash on this op.
+ *
+ * @hide
+ */
+ public int noteProxyOp(int op, String proxiedPackageName) {
+ int mode = noteProxyOpNoThrow(op, proxiedPackageName);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException("Proxy package " + mContext.getOpPackageName()
+ + " from uid " + Process.myUid() + " or calling package "
+ + proxiedPackageName + " from uid " + Binder.getCallingUid()
+ + " not allowed to perform " + sOpNames[op]);
+ }
+ return mode;
+ }
+
+ /**
+ * Like {@link #noteProxyOp(int, String)} but instead
+ * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}.
+ * @hide
+ */
+ public int noteProxyOpNoThrow(int op, String proxiedPackageName) {
+ try {
+ return mService.noteProxyOperation(op, mContext.getOpPackageName(),
+ Binder.getCallingUid(), proxiedPackageName);
+ } catch (RemoteException e) {
+ }
+ return MODE_ERRORED;
+ }
+
+ /**
* Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
* returns {@link #MODE_ERRORED}.
* @hide
@@ -1541,7 +1628,7 @@
return mService.noteOperation(op, uid, packageName);
} catch (RemoteException e) {
}
- return MODE_IGNORED;
+ return MODE_ERRORED;
}
/** @hide */
@@ -1603,7 +1690,7 @@
return mService.startOperation(getToken(mService), op, uid, packageName);
} catch (RemoteException e) {
}
- return MODE_IGNORED;
+ return MODE_ERRORED;
}
/** @hide */
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0420fb6..6639486 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1202,8 +1202,8 @@
validateServiceIntent(service);
service.prepareToLeaveProcess();
ComponentName cn = ActivityManagerNative.getDefault().startService(
- mMainThread.getApplicationThread(), service,
- service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
+ mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
+ getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
@@ -1279,9 +1279,9 @@
}
service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
- mMainThread.getApplicationThread(), getActivityToken(),
- service, service.resolveTypeIfNeeded(getContentResolver()),
- sd, flags, user.getIdentifier());
+ mMainThread.getApplicationThread(), getActivityToken(), service,
+ service.resolveTypeIfNeeded(getContentResolver()),
+ sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 1423e4b..acce81c 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -160,16 +160,16 @@
public PendingIntent getRunningServiceControlPanel(ComponentName service)
throws RemoteException;
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, int userId) throws RemoteException;
+ String resolvedType, String callingPackage, int userId) throws RemoteException;
public int stopService(IApplicationThread caller, Intent service,
String resolvedType, int userId) throws RemoteException;
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) throws RemoteException;
public void setServiceForeground(ComponentName className, IBinder token,
int id, Notification notification, boolean keepNotification) throws RemoteException;
- public int bindService(IApplicationThread caller, IBinder token,
- Intent service, String resolvedType,
- IServiceConnection connection, int flags, int userId) throws RemoteException;
+ public int bindService(IApplicationThread caller, IBinder token, Intent service,
+ String resolvedType, IServiceConnection connection, int flags,
+ String callingPackage, int userId) throws RemoteException;
public boolean unbindService(IServiceConnection connection) throws RemoteException;
public void publishService(IBinder token,
Intent intent, IBinder service) throws RemoteException;
@@ -178,7 +178,8 @@
/* oneway */
public void serviceDoneExecuting(IBinder token, int type, int startId,
int res) throws RemoteException;
- public IBinder peekService(Intent service, String resolvedType) throws RemoteException;
+ public IBinder peekService(Intent service, String resolvedType, String callingPackage)
+ throws RemoteException;
public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
throws RemoteException;
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index af74e73..2260d7e 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -524,7 +524,7 @@
try {
service.prepareToLeaveProcess();
binder = am.peekService(service, service.resolveTypeIfNeeded(
- myContext.getContentResolver()));
+ myContext.getContentResolver()), myContext.getOpPackageName());
} catch (RemoteException e) {
}
return binder;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index d4c4437..3cc7684 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -475,18 +475,38 @@
private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
throws SecurityException {
enforceReadPermissionInner(uri, callerToken);
- if (mReadOp != AppOpsManager.OP_NONE) {
- return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg);
+
+ final int permOp = AppOpsManager.permissionToOpCode(mReadPermission);
+ if (permOp != AppOpsManager.OP_NONE) {
+ final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg);
+ if (mode != AppOpsManager.MODE_ALLOWED) {
+ return mode;
+ }
}
+
+ if (mReadOp != AppOpsManager.OP_NONE) {
+ return mAppOpsManager.noteProxyOp(mReadOp, callingPkg);
+ }
+
return AppOpsManager.MODE_ALLOWED;
}
private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
throws SecurityException {
enforceWritePermissionInner(uri, callerToken);
- if (mWriteOp != AppOpsManager.OP_NONE) {
- return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg);
+
+ final int permOp = AppOpsManager.permissionToOpCode(mWritePermission);
+ if (permOp != AppOpsManager.OP_NONE) {
+ final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg);
+ if (mode != AppOpsManager.MODE_ALLOWED) {
+ return mode;
+ }
}
+
+ if (mWriteOp != AppOpsManager.OP_NONE) {
+ return mAppOpsManager.noteProxyOp(mWriteOp, callingPkg);
+ }
+
return AppOpsManager.MODE_ALLOWED;
}
}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 86c1b2f..201a124aa 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -25,6 +25,8 @@
// be kept in sync with frameworks/native/include/binder/IAppOpsService.h
int checkOperation(int code, int uid, String packageName);
int noteOperation(int code, int uid, String packageName);
+ int noteProxyOperation(int code, String proxyPackageName,
+ int callingUid, String callingPackageName);
int startOperation(IBinder token, int code, int uid, String packageName);
void finishOperation(IBinder token, int code, int uid, String packageName);
void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 79c66b9..f0fc399 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -116,6 +116,8 @@
public final static class Op {
public final int uid;
public final String packageName;
+ public int proxyUid = -1;
+ public String proxyPackageName;
public final int op;
public int mode;
public int duration;
@@ -289,7 +291,8 @@
for (int j=0; j<pkgOps.size(); j++) {
Op curOp = pkgOps.valueAt(j);
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, curOp.duration));
+ curOp.rejectTime, curOp.duration, curOp.proxyUid,
+ curOp.proxyPackageName));
}
} else {
for (int j=0; j<ops.length; j++) {
@@ -299,7 +302,8 @@
resOps = new ArrayList<AppOpsManager.OpEntry>();
}
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, curOp.duration));
+ curOp.rejectTime, curOp.duration, curOp.proxyUid,
+ curOp.proxyPackageName));
}
}
}
@@ -659,9 +663,28 @@
}
@Override
+ public int noteProxyOperation(int code, String proxyPackageName,
+ int proxiedUid, String proxiedPackageName) {
+ verifyIncomingOp(code);
+ final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
+ proxyPackageName, -1, null);
+ if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
+ return proxyMode;
+ }
+ return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
+ Binder.getCallingUid(), proxyPackageName);
+
+ }
+
+ @Override
public int noteOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ return noteOperationUnchecked(code, uid, packageName, 0, null);
+ }
+
+ private int noteOperationUnchecked(int code, int uid, String packageName,
+ int proxyUid, String proxyPackageName) {
synchronized (this) {
Ops ops = getOpsLocked(uid, packageName, true);
if (ops == null) {
@@ -690,6 +713,8 @@
+ " package " + packageName);
op.time = System.currentTimeMillis();
op.rejectTime = 0;
+ op.proxyUid = proxyUid;
+ op.proxyPackageName = proxyPackageName;
return AppOpsManager.MODE_ALLOWED;
}
}
@@ -1051,6 +1076,14 @@
if (dur != null) {
op.duration = Integer.parseInt(dur);
}
+ String proxyUid = parser.getAttributeValue(null, "pu");
+ if (proxyUid != null) {
+ op.proxyUid = Integer.parseInt(proxyUid);
+ }
+ String proxyPackageName = parser.getAttributeValue(null, "pp");
+ if (proxyPackageName != null) {
+ op.proxyPackageName = proxyPackageName;
+ }
HashMap<String, Ops> pkgOps = mUidOps.get(uid);
if (pkgOps == null) {
pkgOps = new HashMap<String, Ops>();
@@ -1132,6 +1165,14 @@
if (dur != 0) {
out.attribute(null, "d", Integer.toString(dur));
}
+ int proxyUid = op.getProxyUid();
+ if (proxyUid != -1) {
+ out.attribute(null, "pu", Integer.toString(proxyUid));
+ }
+ String proxyPackageName = op.getProxyPackageName();
+ if (proxyPackageName != null) {
+ out.attribute(null, "pp", proxyPackageName);
+ }
out.endTag(null, "op");
}
out.endTag(null, "uid");
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 333db5d..899139f 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -29,6 +29,7 @@
import java.util.Set;
import android.app.ActivityThread;
+import android.app.AppOpsManager;
import android.os.Build;
import android.os.DeadObjectException;
import android.os.Handler;
@@ -302,8 +303,8 @@
return getServiceMap(callingUser).mServicesByName;
}
- ComponentName startServiceLocked(IApplicationThread caller, Intent service,
- String resolvedType, int callingPid, int callingUid, int userId)
+ ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
+ int callingPid, int callingUid, String callingPackage, int userId)
throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -324,7 +325,7 @@
ServiceLookupResult res =
- retrieveServiceLocked(service, resolvedType,
+ retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg);
if (res == null) {
return null;
@@ -490,7 +491,7 @@
}
// If this service is active, make sure it is stopped.
- ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
+ ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, null,
Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);
if (r != null) {
if (r.record != null) {
@@ -508,8 +509,8 @@
return 0;
}
- IBinder peekServiceLocked(Intent service, String resolvedType) {
- ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
+ IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
+ ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(),
UserHandle.getCallingUserId(), false, false);
@@ -694,8 +695,8 @@
}
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
- String resolvedType, IServiceConnection connection, int flags, int userId)
- throws TransactionTooLargeException {
+ String resolvedType, IServiceConnection connection, int flags,
+ String callingPackage, int userId) throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
@@ -746,7 +747,7 @@
final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
ServiceLookupResult res =
- retrieveServiceLocked(service, resolvedType,
+ retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
if (res == null) {
return 0;
@@ -1022,7 +1023,7 @@
}
private ServiceLookupResult retrieveServiceLocked(Intent service,
- String resolvedType, int callingPid, int callingUid, int userId,
+ String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg) {
ServiceRecord r = null;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
@@ -1112,7 +1113,18 @@
+ ", uid=" + callingUid
+ " requires " + r.permission);
return new ServiceLookupResult(null, r.permission);
+ } else if (r.permission != null && callingPackage != null) {
+ final int opCode = AppOpsManager.permissionToOpCode(r.permission);
+ if (opCode != AppOpsManager.OP_NONE && mAm.mAppOpsService.noteOperation(
+ opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: Accessing service " + r.name
+ + " from pid=" + callingPid
+ + ", uid=" + callingUid
+ + " requires appop " + AppOpsManager.opToName(opCode));
+ return null;
+ }
}
+
if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
resolvedType, r.appInfo)) {
return null;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d3c8b16..7c537c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15580,13 +15580,18 @@
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, int userId) throws TransactionTooLargeException {
+ String resolvedType, String callingPackage, int userId)
+ throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ if (callingPackage == null) {
+ throw new IllegalArgumentException("callingPackage cannot be null");
+ }
+
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startService: " + service + " type=" + resolvedType);
synchronized(this) {
@@ -15594,20 +15599,21 @@
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
- resolvedType, callingPid, callingUid, userId);
+ resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
- ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, int userId)
+ ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
+ String callingPackage, int userId)
throws TransactionTooLargeException {
synchronized(this) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startServiceInPackage: " + service + " type=" + resolvedType);
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, userId);
+ resolvedType, -1, uid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
@@ -15628,14 +15634,19 @@
}
@Override
- public IBinder peekService(Intent service, String resolvedType) {
+ public IBinder peekService(Intent service, String resolvedType, String callingPackage) {
enforceNotIsolatedCaller("peekService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+
+ if (callingPackage == null) {
+ throw new IllegalArgumentException("callingPackage cannot be null");
+ }
+
synchronized(this) {
- return mServices.peekServiceLocked(service, resolvedType);
+ return mServices.peekServiceLocked(service, resolvedType, callingPackage);
}
}
@@ -15805,8 +15816,8 @@
}
public int bindService(IApplicationThread caller, IBinder token, Intent service,
- String resolvedType, IServiceConnection connection, int flags, int userId)
- throws TransactionTooLargeException {
+ String resolvedType, IServiceConnection connection, int flags, String callingPackage,
+ int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
@@ -15814,9 +15825,13 @@
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ if (callingPackage == null) {
+ throw new IllegalArgumentException("callingPackage cannot be null");
+ }
+
synchronized(this) {
- return mServices.bindServiceLocked(caller, token, service, resolvedType,
- connection, flags, userId);
+ return mServices.bindServiceLocked(caller, token, service,
+ resolvedType, connection, flags, callingPackage, userId);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f1c123e..105e36c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -187,12 +187,12 @@
Manifest.permission.CALL_PHONE);
}
- /** Action not restricted for the calling package. */
- private static final int ACTION_RESTRICTION_NONE = 0;
- /** Action restricted for the calling package by not granting a used permission. */
- private static final int ACTION_RESTRICTION_PERMISSION = 1;
- /** Action restricted for the calling package by not allowing a used permission's app op. */
- private static final int ACTION_RESTRICTION_APPOP = 2;
+ /** Action restriction: launching the activity is not restricted. */
+ private static final int ACTIVITY_RESTRICTION_NONE = 0;
+ /** Action restriction: launching the activity is restricted by a permission. */
+ private static final int ACTIVITY_RESTRICTION_PERMISSION = 1;
+ /** Action restriction: launching the activity is restricted by an app op. */
+ private static final int ACTIVITY_RESTRICTION_APPOP = 2;
/** Status Bar Service **/
private IBinder mToken = new Binder();
@@ -1539,51 +1539,61 @@
return err;
}
- final int startAnyPerm = mService.checkPermission(
- START_ANY_ACTIVITY, callingPid, callingUid);
- final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
- callingUid, aInfo.applicationInfo.uid, aInfo.exported);
- final int actionRestriction = getActionRestrictionForCallingPackage(
- intent.getAction(), callingPackage, callingPid, callingUid);
-
- if (startAnyPerm != PERMISSION_GRANTED && (componentPerm != PERMISSION_GRANTED
- || actionRestriction == ACTION_RESTRICTION_PERMISSION)) {
- if (resultRecord != null) {
- resultStack.sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- String msg;
- if (actionRestriction == ACTION_RESTRICTION_PERMISSION) {
- msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")" + " with revoked permission "
- + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
- } else if (!aInfo.exported) {
- msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " not exported from uid " + aInfo.applicationInfo.uid;
- } else {
- msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " requires " + aInfo.permission;
- }
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
-
boolean abort = false;
- if (startAnyPerm != PERMISSION_GRANTED
- && actionRestriction == ACTION_RESTRICTION_APPOP) {
- String msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " requires " + aInfo.permission;
- Slog.w(TAG, msg);
- abort = true;
+ final int startAnyPerm = mService.checkPermission(
+ START_ANY_ACTIVITY, callingPid, callingUid);
+
+ if (startAnyPerm != PERMISSION_GRANTED) {
+ final int componentRestriction = getComponentRestrictionForCallingPackage(
+ aInfo, callingPackage, callingPid, callingUid);
+ final int actionRestriction = getActionRestrictionForCallingPackage(
+ intent.getAction(), callingPackage, callingPid, callingUid);
+
+ if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION
+ || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
+ if (resultRecord != null) {
+ resultStack.sendActivityResultLocked(-1,
+ resultRecord, resultWho, requestCode,
+ Activity.RESULT_CANCELED, null);
+ }
+ String msg;
+ if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
+ msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")" + " with revoked permission "
+ + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
+ } else if (!aInfo.exported) {
+ msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " not exported from uid " + aInfo.applicationInfo.uid;
+ } else {
+ msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " requires " + aInfo.permission;
+ }
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) {
+ String message = "Appop Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " requires " + AppOpsManager.permissionToOp(
+ ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()));
+ Slog.w(TAG, message);
+ abort = true;
+ } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) {
+ String message = "Appop Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission);
+ Slog.w(TAG, message);
+ abort = true;
+ }
}
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
@@ -1664,15 +1674,40 @@
return err;
}
+ private int getComponentRestrictionForCallingPackage(ActivityInfo activityInfo,
+ String callingPackage, int callingPid, int callingUid) {
+ if (activityInfo.permission == null) {
+ return ACTIVITY_RESTRICTION_NONE;
+ }
+
+ if (mService.checkComponentPermission(activityInfo.permission, callingPid, callingUid,
+ activityInfo.applicationInfo.uid, activityInfo.exported)
+ == PackageManager.PERMISSION_DENIED) {
+ return ACTIVITY_RESTRICTION_PERMISSION;
+ }
+
+ final int opCode = AppOpsManager.permissionToOpCode(activityInfo.permission);
+ if (opCode == AppOpsManager.OP_NONE) {
+ return ACTIVITY_RESTRICTION_NONE;
+ }
+
+ if (mService.mAppOpsService.noteOperation(opCode, callingUid,
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return ACTIVITY_RESTRICTION_APPOP;
+ }
+
+ return ACTIVITY_RESTRICTION_NONE;
+ }
+
private int getActionRestrictionForCallingPackage(String action,
String callingPackage, int callingPid, int callingUid) {
if (action == null) {
- return ACTION_RESTRICTION_NONE;
+ return ACTIVITY_RESTRICTION_NONE;
}
String permission = ACTION_TO_RUNTIME_PERMISSION.get(action);
if (permission == null) {
- return ACTION_RESTRICTION_NONE;
+ return ACTIVITY_RESTRICTION_NONE;
}
final PackageInfo packageInfo;
@@ -1681,29 +1716,29 @@
.getPackageInfo(callingPackage, PackageManager.GET_PERMISSIONS);
} catch (PackageManager.NameNotFoundException e) {
Slog.i(TAG, "Cannot find package info for " + callingPackage);
- return ACTION_RESTRICTION_NONE;
+ return ACTIVITY_RESTRICTION_NONE;
}
if (!ArrayUtils.contains(packageInfo.requestedPermissions, permission)) {
- return ACTION_RESTRICTION_NONE;
+ return ACTIVITY_RESTRICTION_NONE;
}
if (mService.checkPermission(permission, callingPid, callingUid) ==
PackageManager.PERMISSION_DENIED) {
- return ACTION_RESTRICTION_PERMISSION;
+ return ACTIVITY_RESTRICTION_PERMISSION;
}
final int opCode = AppOpsManager.permissionToOpCode(permission);
if (opCode == AppOpsManager.OP_NONE) {
- return ACTION_RESTRICTION_NONE;
+ return ACTIVITY_RESTRICTION_NONE;
}
if (mService.mAppOpsService.noteOperation(opCode, callingUid,
callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return ACTION_RESTRICTION_APPOP;
+ return ACTIVITY_RESTRICTION_APPOP;
}
- return ACTION_RESTRICTION_NONE;
+ return ACTIVITY_RESTRICTION_NONE;
}
ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2335071..30aa411 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -463,7 +463,7 @@
}
}
- private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
+ private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered) {
boolean skip = false;
if (filter.requiredPermission != null) {
@@ -477,9 +477,23 @@
+ " requires " + filter.requiredPermission
+ " due to registered receiver " + filter);
skip = true;
+ } else {
+ final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
+ if (opCode != AppOpsManager.OP_NONE
+ && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
+ r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid="
+ + r.callingPid + ", uid=" + r.callingUid + ")"
+ + " requires appop " + AppOpsManager.permissionToOp(
+ filter.requiredPermission)
+ + " due to registered receiver " + filter);
+ skip = true;
+ }
}
}
- if (!skip && r.requiredPermission != null) {
+ if (!skip) {
int perm = mService.checkComponentPermission(r.requiredPermission,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
@@ -493,17 +507,42 @@
+ " (uid " + r.callingUid + ")");
skip = true;
}
- }
- if (r.appOp != AppOpsManager.OP_NONE) {
- int mode = mService.mAppOpsService.noteOperation(r.appOp,
- filter.receiverList.uid, filter.packageName);
- if (mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
- "App op " + r.appOp + " not allowed for broadcast to uid "
- + filter.receiverList.uid + " pkg " + filter.packageName);
- skip = true;
+ int appOp = AppOpsManager.OP_NONE;
+ if (r.requiredPermission != null) {
+ appOp = AppOpsManager.permissionToOpCode(r.requiredPermission);
+ if (appOp != AppOpsManager.OP_NONE
+ && mService.mAppOpsService.noteOperation(appOp,
+ filter.receiverList.uid, filter.packageName)
+ != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: receiving "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ", uid=" + filter.receiverList.uid + ")"
+ + " requires appop " + AppOpsManager.permissionToOp(
+ r.requiredPermission)
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+ if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE
+ && mService.mAppOpsService.noteOperation(r.appOp,
+ filter.receiverList.uid, filter.packageName)
+ != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: receiving "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ", uid=" + filter.receiverList.uid + ")"
+ + " requires appop " + AppOpsManager.permissionToOp(
+ r.requiredPermission)
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
}
}
+
if (!skip) {
skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, filter.receiverList.uid);
@@ -804,8 +843,23 @@
+ " due to receiver " + component.flattenToShortString());
}
skip = true;
+ } else if (info.activityInfo.permission != null) {
+ final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
+ if (opCode != AppOpsManager.OP_NONE
+ && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
+ r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid="
+ + r.callingPid + ", uid=" + r.callingUid + ")"
+ + " requires appop " + AppOpsManager.permissionToOp(
+ info.activityInfo.permission)
+ + " due to registered receiver "
+ + component.flattenToShortString());
+ skip = true;
+ }
}
- if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
+ if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermission != null) {
try {
perm = AppGlobals.getPackageManager().
@@ -825,17 +879,36 @@
skip = true;
}
}
- if (r.appOp != AppOpsManager.OP_NONE) {
- int mode = mService.mAppOpsService.noteOperation(r.appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
- if (mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
- "App op " + r.appOp + " not allowed for broadcast to uid "
- + info.activityInfo.applicationInfo.uid + " pkg "
- + info.activityInfo.packageName);
+ int appOp = AppOpsManager.OP_NONE;
+ if (!skip && r.requiredPermission != null) {
+ appOp = AppOpsManager.permissionToOpCode(r.requiredPermission);
+ if (appOp != AppOpsManager.OP_NONE
+ && mService.mAppOpsService.noteOperation(appOp,
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
+ != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: receiving "
+ + r.intent + " to "
+ + component.flattenToShortString()
+ + " requires appop " + AppOpsManager.permissionToOp(
+ r.requiredPermission)
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
skip = true;
}
}
+ if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE
+ && mService.mAppOpsService.noteOperation(r.appOp,
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
+ != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: receiving "
+ + r.intent + " to "
+ + component.flattenToShortString()
+ + " requires appop " + AppOpsManager.permissionToOp(
+ r.requiredPermission)
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
if (!skip) {
skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index ece3ffb..5b46799 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -305,7 +305,8 @@
break;
case ActivityManager.INTENT_SENDER_SERVICE:
try {
- owner.startServiceInPackage(uid, finalIntent, resolvedType, userId);
+ owner.startServiceInPackage(uid, finalIntent,
+ resolvedType, key.packageName, userId);
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startService intent", e);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 352e953..305eb8e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9198,7 +9198,8 @@
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
- am.startService(null, intent, null, UserHandle.USER_OWNER);
+ am.startService(null, intent, null, mContext.getOpPackageName(),
+ UserHandle.USER_OWNER);
} catch (RemoteException e) {
}
}