Apply AttributionSource during Intent delivery.

There are some Parcelables which offer to perform Binder calls, and
when these are delivered via Intent extras they fallback to
ActivityThread.currentAttributionSource(), instead of being tagged
based on the relevant app component.

This change begins using Intent.prepareToEnterProcess() as a hook to
fix-up AttributionSource when those extras finally land in the
destination process.  It uses the relevant AttributionSource based
on the Activity or Service the Intent is delivered to, which
developers have control over via AppComponentFactory.

In the case of <receiver> manifest elements, this change applies the
first android:attributionTags value to the Context used for that
BroadcastReceiver.

Bug: 187097694
Test: atest AttributionTest
Change-Id: I8f5197db7e8d7277d34f0ef2bb90bfdf1871186a
This commit is contained in:
Jeff Sharkey
2021-05-07 10:28:59 -06:00
parent 3bf189f78b
commit dd6dd3b1fb
7 changed files with 43 additions and 15 deletions

View File

@@ -3509,7 +3509,8 @@ public final class ActivityThread extends ClientTransactionHandler
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
activity.getAttributionSource());
if (r.state != null) {
r.state.setClassLoader(cl);
}
@@ -3801,7 +3802,8 @@ public final class ActivityThread extends ClientTransactionHandler
for (int i=0; i<N; i++) {
ReferrerIntent intent = intents.get(i);
intent.setExtrasClassLoader(r.activity.getClassLoader());
intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
r.activity.getAttributionSource());
r.activity.mFragments.noteStateNotSaved();
mInstrumentation.callActivityOnNewIntent(r.activity, intent);
}
@@ -4241,10 +4243,15 @@ public final class ActivityThread extends ClientTransactionHandler
if (data.info.splitName != null) {
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
}
if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
final String attributionTag = data.info.attributionTags[0];
context = (ContextImpl) context.createAttributionContext(attributionTag);
}
java.lang.ClassLoader cl = context.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess(
isProtectedComponent(data.info) || isProtectedBroadcast(data.intent));
isProtectedComponent(data.info) || isProtectedBroadcast(data.intent),
context.getAttributionSource());
data.setExtrasClassLoader(cl);
receiver = packageInfo.getAppFactory()
.instantiateReceiver(cl, data.info.name, data.intent);
@@ -4469,7 +4476,8 @@ public final class ActivityThread extends ClientTransactionHandler
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess(isProtectedComponent(createData.info));
data.intent.prepareToEnterProcess(isProtectedComponent(createData.info),
s.getAttributionSource());
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
@@ -4499,7 +4507,8 @@ public final class ActivityThread extends ClientTransactionHandler
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess(isProtectedComponent(createData.info));
data.intent.prepareToEnterProcess(isProtectedComponent(createData.info),
s.getAttributionSource());
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
@@ -4588,7 +4597,8 @@ public final class ActivityThread extends ClientTransactionHandler
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess(isProtectedComponent(createData.info));
data.args.prepareToEnterProcess(isProtectedComponent(createData.info),
s.getAttributionSource());
}
int res;
if (!data.taskRemoved) {
@@ -5241,7 +5251,8 @@ public final class ActivityThread extends ClientTransactionHandler
try {
if (ri.mData != null) {
ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
ri.mData.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
ri.mData.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
r.activity.getAttributionSource());
}
if (DEBUG_RESULTS) Slog.v(TAG,
"Delivering result to activity " + r + " : " + ri);

View File

@@ -1774,7 +1774,8 @@ class ContextImpl extends Context {
intent.setExtrasClassLoader(getClassLoader());
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent));
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
getAttributionSource());
}
return intent;
} catch (RemoteException e) {

View File

@@ -1651,7 +1651,8 @@ public final class LoadedApk {
intent.setExtrasClassLoader(cl);
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent));
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
mContext.getAttributionSource());
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);

View File

@@ -1190,6 +1190,11 @@ public final class BluetoothDevice implements Parcelable {
return devices;
}
/** {@hide} */
public void prepareToEnterProcess(AttributionSource attributionSource) {
setAttributionSource(attributionSource);
}
@Override
public boolean equals(@Nullable Object o) {
if (o instanceof BluetoothDevice) {

View File

@@ -1034,14 +1034,14 @@ public class ClipData implements Parcelable {
}
/** {@hide} */
public void prepareToEnterProcess() {
public void prepareToEnterProcess(AttributionSource source) {
final int size = mItems.size();
for (int i = 0; i < size; i++) {
final Item item = mItems.get(i);
if (item.mIntent != null) {
// We can't recursively claim that this data is from a protected
// component, since it may have been filled in by a malicious app
item.mIntent.prepareToEnterProcess(false);
item.mIntent.prepareToEnterProcess(false, source);
}
}
}

View File

@@ -31,6 +31,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.AppGlobals;
import android.bluetooth.BluetoothDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -11439,7 +11440,7 @@ public class Intent implements Parcelable, Cloneable {
/**
* @hide
*/
public void prepareToEnterProcess(boolean fromProtectedComponent) {
public void prepareToEnterProcess(boolean fromProtectedComponent, AttributionSource source) {
// We just entered destination process, so we should be able to read all
// parcelables inside.
setDefusable(true);
@@ -11447,10 +11448,10 @@ public class Intent implements Parcelable, Cloneable {
if (mSelector != null) {
// We can't recursively claim that this data is from a protected
// component, since it may have been filled in by a malicious app
mSelector.prepareToEnterProcess(false);
mSelector.prepareToEnterProcess(false, source);
}
if (mClipData != null) {
mClipData.prepareToEnterProcess();
mClipData.prepareToEnterProcess(source);
}
if (mContentUserHint != UserHandle.USER_CURRENT) {
@@ -11463,6 +11464,14 @@ public class Intent implements Parcelable, Cloneable {
if (fromProtectedComponent) {
mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT;
}
// Special attribution fix-up logic for any BluetoothDevice extras
// passed via Bluetooth intents
if (mAction != null && mAction.startsWith("android.bluetooth.")
&& hasExtra(BluetoothDevice.EXTRA_DEVICE)) {
final BluetoothDevice device = getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
device.prepareToEnterProcess(source);
}
}
/** @hide */

View File

@@ -7505,7 +7505,8 @@ public final class ViewRootImpl implements ViewParent,
final View prevDragView = mCurrentDragView;
if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
event.mClipData.prepareToEnterProcess();
event.mClipData.prepareToEnterProcess(
mView.getContext().getAttributionSource());
}
// Now dispatch the drag/drop event