Merge "Update ownership of the Desktop Experience flags." into main
diff --git a/Android.bp b/Android.bp
index b3c930a..c1a8012 100644
--- a/Android.bp
+++ b/Android.bp
@@ -520,11 +520,7 @@
],
},
jarjar_prefix: "com.android.internal.hidden_from_bootclasspath",
-
- jarjar_shards: select(release_flag("RELEASE_USE_SHARDED_JARJAR_ON_FRAMEWORK_MINUS_APEX"), {
- true: "10",
- default: "1",
- }),
+ jarjar_shards: "10",
}
java_library {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8a85406..a624994 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -6950,7 +6950,7 @@
Slog.w(TAG, "Low overhead tracing feature is not enabled");
break;
}
- VMDebug.startLowOverheadTrace();
+ VMDebug.startLowOverheadTraceForAllMethods();
break;
default:
try {
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index 37604bc..1de8a24 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,7 +1,7 @@
# Bug component: 175220
-anothermark@google.com
+vmartensson@google.com
+nkapron@google.com
febinthattil@google.com
-aprasath@google.com
+shubhankarm@google.com
badhri@google.com
-kumarashishg@google.com
\ No newline at end of file
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ed75491..86dc20c 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -149,6 +149,11 @@
private static volatile boolean sStackTrackingEnabled = false;
/**
+ * The extension binder object
+ */
+ private IBinder mExtension = null;
+
+ /**
* Enable Binder IPC stack tracking. If enabled, every binder transaction will be logged to
* {@link TransactionTracker}.
*
@@ -1234,7 +1239,9 @@
/** @hide */
@Override
- public final native @Nullable IBinder getExtension();
+ public final @Nullable IBinder getExtension() {
+ return mExtension;
+ }
/**
* Set the binder extension.
@@ -1242,7 +1249,12 @@
*
* @hide
*/
- public final native void setExtension(@Nullable IBinder extension);
+ public final void setExtension(@Nullable IBinder extension) {
+ mExtension = extension;
+ setExtensionNative(extension);
+ }
+
+ private final native void setExtensionNative(@Nullable IBinder extension);
/**
* Default implementation rewinds the parcels and calls onTransact. On
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 7877352..c91a330 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -190,7 +190,7 @@
}
public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
- if (mLeash != null) {
+ if (mLeash != null && mLeash.isValid()) {
surfaceReleaseConsumer.accept(mLeash);
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d129762..83750ac 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1051,7 +1051,7 @@
}
final int patternSize = pattern.size();
- byte[] res = new byte[patternSize];
+ byte[] res = newNonMovableByteArray(patternSize);
for (int i = 0; i < patternSize; i++) {
LockPatternView.Cell cell = pattern.get(i);
res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index 92ce990..2a12c98 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -81,9 +81,9 @@
/**
* Private constructor, use static builder methods instead.
*
- * <p> Builder methods should create a private copy of the credential bytes and pass in here.
- * LockscreenCredential will only store the reference internally without copying. This is to
- * minimize the number of extra copies introduced.
+ * <p> Builder methods should create a private copy of the credential bytes using a non-movable
+ * array and pass it in here. LockscreenCredential will only store the reference internally
+ * without copying. This is to minimize the number of extra copies introduced.
*/
private LockscreenCredential(int type, byte[] credential, boolean hasInvalidChars) {
Objects.requireNonNull(credential);
@@ -141,7 +141,7 @@
*/
public static LockscreenCredential createUnifiedProfilePassword(@NonNull byte[] password) {
return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
- Arrays.copyOf(password, password.length), /* hasInvalidChars= */ false);
+ copyOfArrayNonMovable(password), /* hasInvalidChars= */ false);
}
/**
@@ -237,7 +237,7 @@
/** Create a copy of the credential */
public LockscreenCredential duplicate() {
return new LockscreenCredential(mType,
- mCredential != null ? Arrays.copyOf(mCredential, mCredential.length) : null,
+ mCredential != null ? copyOfArrayNonMovable(mCredential) : null,
mHasInvalidChars);
}
@@ -252,6 +252,15 @@
}
/**
+ * Copies the given array into a new non-movable array.
+ */
+ private static byte[] copyOfArrayNonMovable(byte[] array) {
+ byte[] copy = LockPatternUtils.newNonMovableByteArray(array.length);
+ System.arraycopy(array, 0, copy, 0, array.length);
+ return copy;
+ }
+
+ /**
* Checks whether the credential meets basic requirements for setting it as a new credential.
*
* This is redundant if {@link android.app.admin.PasswordMetrics#validateCredential()}, which
@@ -440,7 +449,7 @@
* @return A byte array representing the input
*/
private static byte[] charsToBytesTruncating(CharSequence chars) {
- byte[] bytes = new byte[chars.length()];
+ byte[] bytes = LockPatternUtils.newNonMovableByteArray(chars.length());
for (int i = 0; i < chars.length(); i++) {
bytes[i] = (byte) chars.charAt(i);
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 8003bb7..e85b33e 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -74,6 +74,7 @@
jmethodID mExecTransact;
jmethodID mGetInterfaceDescriptor;
jmethodID mTransactionCallback;
+ jmethodID mGetExtension;
// Object state.
jfieldID mObject;
@@ -489,8 +490,12 @@
if (mVintf) {
::android::internal::Stability::markVintf(b.get());
}
- if (mExtension != nullptr) {
- b.get()->setExtension(mExtension);
+ if (mSetExtensionCalled) {
+ jobject javaIBinderObject = env->CallObjectMethod(obj, gBinderOffsets.mGetExtension);
+ sp<IBinder> extensionFromJava = ibinderForJavaObject(env, javaIBinderObject);
+ if (extensionFromJava != nullptr) {
+ b.get()->setExtension(extensionFromJava);
+ }
}
mBinder = b;
ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
@@ -516,21 +521,12 @@
mVintf = false;
}
- sp<IBinder> getExtension() {
- AutoMutex _l(mLock);
- sp<JavaBBinder> b = mBinder.promote();
- if (b != nullptr) {
- return b.get()->getExtension();
- }
- return mExtension;
- }
-
void setExtension(const sp<IBinder>& extension) {
AutoMutex _l(mLock);
- mExtension = extension;
+ mSetExtensionCalled = true;
sp<JavaBBinder> b = mBinder.promote();
if (b != nullptr) {
- b.get()->setExtension(mExtension);
+ b.get()->setExtension(extension);
}
}
@@ -542,8 +538,7 @@
// is too much binder state here, we can think about making JavaBBinder an
// sp here (avoid recreating it)
bool mVintf = false;
-
- sp<IBinder> mExtension;
+ bool mSetExtensionCalled = false;
};
// ----------------------------------------------------------------------------
@@ -1249,10 +1244,6 @@
return IPCThreadState::self()->blockUntilThreadAvailable();
}
-static jobject android_os_Binder_getExtension(JNIEnv* env, jobject obj) {
- JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject);
- return javaObjectForIBinder(env, jbh->getExtension());
-}
static void android_os_Binder_setExtension(JNIEnv* env, jobject obj, jobject extensionObject) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject);
@@ -1295,8 +1286,7 @@
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
{ "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable },
- { "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
- { "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
+ { "setExtensionNative", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
};
// clang-format on
@@ -1313,6 +1303,8 @@
gBinderOffsets.mTransactionCallback =
GetStaticMethodIDOrDie(env, clazz, "transactionCallback", "(IIII)V");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
+ gBinderOffsets.mGetExtension = GetMethodIDOrDie(env, clazz, "getExtension",
+ "()Landroid/os/IBinder;");
return RegisterMethodsOrDie(
env, kBinderPathName,
diff --git a/media/java/android/mtp/OWNERS b/media/java/android/mtp/OWNERS
index 77ed08b..c57265a 100644
--- a/media/java/android/mtp/OWNERS
+++ b/media/java/android/mtp/OWNERS
@@ -1,9 +1,9 @@
set noparent
-anothermark@google.com
+vmartensson@google.com
+nkapron@google.com
febinthattil@google.com
-aprasath@google.com
+shubhankarm@google.com
jsharkey@android.com
jameswei@google.com
rmojumder@google.com
-kumarashishg@google.com
diff --git a/media/jni/OWNERS b/media/jni/OWNERS
index e12d828..fdddf13 100644
--- a/media/jni/OWNERS
+++ b/media/jni/OWNERS
@@ -4,5 +4,5 @@
# extra for TV related files
per-file android_media_tv_*=hgchen@google.com,quxiangfang@google.com
-per-file android_media_JetPlayer.cpp,android_media_MediaDataSource.cpp,android_media_MediaDataSource.h,android_media_MediaPlayer.java=set noparent
-per-file android_media_JetPlayer.cpp,android_media_MediaDataSource.cpp,android_media_MediaDataSource.h,android_media_MediaPlayer.java=file:platform/frameworks/av:/media/janitors/media_solutions_OWNERS
+per-file android_media_JetPlayer.cpp,android_media_MediaDataSource.cpp,android_media_MediaDataSource.h,android_media_MediaPlayer.cpp=set noparent
+per-file android_media_JetPlayer.cpp,android_media_MediaDataSource.cpp,android_media_MediaDataSource.h,android_media_MediaPlayer.cpp=file:platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index a77bc9f..a1ce495 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -910,7 +910,7 @@
case MTP_FORMAT_TIFF:
case MTP_FORMAT_TIFF_EP:
case MTP_FORMAT_DEFINED: {
- String8 temp(path);
+ String8 temp {static_cast<std::string_view>(path)};
std::unique_ptr<FileStream> stream(new FileStream(temp));
piex::PreviewImageData image_data;
if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
@@ -967,7 +967,7 @@
case MTP_FORMAT_TIFF:
case MTP_FORMAT_TIFF_EP:
case MTP_FORMAT_DEFINED: {
- String8 temp(path);
+ String8 temp {static_cast<std::string_view>(path)};
std::unique_ptr<FileStream> stream(new FileStream(temp));
piex::PreviewImageData image_data;
if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
diff --git a/media/tests/MtpTests/OWNERS b/media/tests/MtpTests/OWNERS
index bdb6cdb..c57265a 100644
--- a/media/tests/MtpTests/OWNERS
+++ b/media/tests/MtpTests/OWNERS
@@ -1,9 +1,9 @@
set noparent
-anothermark@google.com
+vmartensson@google.com
+nkapron@google.com
febinthattil@google.com
-aprasath@google.com
+shubhankarm@google.com
jsharkey@android.com
jameswei@google.com
rmojumder@google.com
-kumarashishg@google.com
\ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index ff08403..60fae3f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -18,10 +18,13 @@
import static android.os.Process.FIRST_APPLICATION_UID;
+import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon;
+
import android.aconfig.Aconfig.flag_permission;
import android.aconfig.Aconfig.flag_state;
import android.aconfig.Aconfig.parsed_flag;
import android.aconfig.Aconfig.parsed_flags;
+import android.aconfigd.AconfigdFlagInfo;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -65,14 +68,10 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.PosixFileAttributes;
-import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -84,18 +83,6 @@
import java.util.Set;
import java.util.concurrent.CountDownLatch;
-// FOR ACONFIGD TEST MISSION AND ROLLOUT
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import android.util.proto.ProtoInputStream;
-import android.aconfigd.Aconfigd.StorageRequestMessage;
-import android.aconfigd.Aconfigd.StorageRequestMessages;
-import android.aconfigd.Aconfigd.StorageReturnMessage;
-import android.aconfigd.Aconfigd.StorageReturnMessages;
-import android.aconfigd.AconfigdClientSocket;
-import android.aconfigd.AconfigdFlagInfo;
-import android.aconfigd.AconfigdJavaUtils;
-import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon;
/**
* This class contains the state for one type of settings. It is responsible
* for saving the state asynchronously to an XML file after a mutation and
@@ -393,22 +380,6 @@
getAllAconfigFlagsFromSettings(mAconfigDefaultFlags);
}
}
-
- if (isConfigSettingsKey(mKey)) {
- requests = handleBulkSyncToNewStorage(mAconfigDefaultFlags);
- }
- }
-
- if (enableAconfigStorageDaemon()) {
- if (isConfigSettingsKey(mKey)){
- AconfigdClientSocket localSocket = AconfigdJavaUtils.getAconfigdClientSocket();
- if (requests != null) {
- InputStream res = localSocket.send(requests.getBytes());
- if (res == null) {
- Slog.w(LOG_TAG, "Bulk sync request to acongid failed.");
- }
- }
- }
}
}
@@ -482,87 +453,6 @@
return flag;
}
-
- // TODO(b/341764371): migrate aconfig flag push to GMS core
- @VisibleForTesting
- @GuardedBy("mLock")
- public ProtoOutputStream handleBulkSyncToNewStorage(
- Map<String, AconfigdFlagInfo> aconfigFlagMap) {
- // get marker or add marker if it does not exist
- Setting markerSetting = mSettings.get(BULK_SYNC_MARKER);
- int localCounter = 0;
- if (markerSetting == null) {
- markerSetting = new Setting(BULK_SYNC_MARKER, "0", false, "aconfig", "aconfig");
- mSettings.put(BULK_SYNC_MARKER, markerSetting);
- }
- try {
- localCounter = Integer.parseInt(markerSetting.value);
- } catch (NumberFormatException e) {
- // reset local counter
- markerSetting.value = "0";
- }
-
- if (enableAconfigStorageDaemon()) {
- Setting bulkSyncCounter = mSettings.get(BULK_SYNC_TRIGGER_COUNTER);
- int serverCounter = 0;
- if (bulkSyncCounter != null) {
- try {
- serverCounter = Integer.parseInt(bulkSyncCounter.value);
- } catch (NumberFormatException e) {
- // reset the local value of server counter
- bulkSyncCounter.value = "0";
- }
- }
-
- boolean shouldSync = localCounter < serverCounter;
- if (!shouldSync) {
- // CASE 1, flag is on, bulk sync marker true, nothing to do
- return null;
- } else {
- // CASE 2, flag is on, bulk sync marker false. Do following two tasks
- // (1) Do bulk sync here.
- // (2) After bulk sync, set marker to true.
-
- // first add storage reset request
- ProtoOutputStream requests = new ProtoOutputStream();
- AconfigdJavaUtils.writeResetStorageRequest(requests);
-
- // loop over all settings and add flag override requests
- for (AconfigdFlagInfo flag : aconfigFlagMap.values()) {
- // don't sync read_only flags
- if (!flag.getIsReadWrite()) {
- continue;
- }
-
- if (flag.getHasServerOverride()) {
- AconfigdJavaUtils.writeFlagOverrideRequest(
- requests,
- flag.getPackageName(),
- flag.getFlagName(),
- flag.getServerFlagValue(),
- StorageRequestMessage.SERVER_ON_REBOOT);
- }
-
- if (flag.getHasLocalOverride()) {
- AconfigdJavaUtils.writeFlagOverrideRequest(
- requests,
- flag.getPackageName(),
- flag.getFlagName(),
- flag.getLocalFlagValue(),
- StorageRequestMessage.LOCAL_ON_REBOOT);
- }
- }
-
- // mark sync has been done
- markerSetting.value = String.valueOf(serverCounter);
- scheduleWriteIfNeededLocked();
- return requests;
- }
- } else {
- return null;
- }
- }
-
@GuardedBy("mLock")
private void loadAconfigDefaultValuesLocked(List<String> filePaths) {
for (String fileName : filePaths) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index f798a35..81e1aa8 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -30,19 +30,20 @@
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Xml;
-import android.util.proto.ProtoOutputStream;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.TypedXmlSerializer;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
-
import com.google.common.base.Strings;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -51,11 +52,6 @@
import java.util.List;
import java.util.Map;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SettingsStateTest {
@@ -1084,124 +1080,6 @@
assertTrue(flag1.getHasLocalOverride());
}
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
- @Test
- @EnableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON)
- public void testHandleBulkSyncWithAconfigdEnabled() {
- int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
- Object lock = new Object();
- SettingsState settingsState =
- new SettingsState(
- InstrumentationRegistry.getContext(),
- lock,
- mSettingsFile,
- configKey,
- SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED,
- Looper.getMainLooper());
-
- Map<String, AconfigdFlagInfo> flags = new HashMap<>();
- flags.put(
- "com.android.flags/flag1",
- AconfigdFlagInfo.newBuilder()
- .setPackageName("com.android.flags")
- .setFlagName("flag1")
- .setBootFlagValue("true")
- .setIsReadWrite(true)
- .build());
-
- flags.put(
- "com.android.flags/flag2",
- AconfigdFlagInfo.newBuilder()
- .setPackageName("com.android.flags")
- .setFlagName("flag2")
- .setBootFlagValue("true")
- .setIsReadWrite(false)
- .build());
-
- String bulkSyncMarker = "aconfigd_marker/bulk_synced";
- String bulkSyncCounter =
- "core_experiments_team_internal/" +
- "BulkSyncTriggerCounterFlag__bulk_sync_trigger_counter";
-
- synchronized (lock) {
- settingsState.insertSettingLocked(bulkSyncMarker, "0", null, false, "aconfig");
- settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false,
- "com.google.android.platform.core_experiments_team_internal");
-
- // first bulk sync
- ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertTrue(requests != null);
- String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("1", value);
-
- // send time should no longer bulk sync
- requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertNull(requests);
- value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("1", value);
-
- // won't sync if the marker is string
- settingsState.insertSettingLocked(bulkSyncMarker, "true", null, false, "aconfig");
- settingsState.insertSettingLocked(bulkSyncCounter, "0", null, false,
- "com.google.android.platform.core_experiments_team_internal");
- requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertNull(requests);
- value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("0", value);
-
- // won't sync if the marker and counter value are the same
- settingsState.insertSettingLocked(bulkSyncMarker, "1", null, false, "aconfig");
- settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false,
- "com.google.android.platform.core_experiments_team_internal");
- requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertNull(requests);
- value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("1", value);
- }
- }
-
- @Test
- @DisableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON)
- public void testHandleBulkSyncWithAconfigdDisabled() {
- int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
- Object lock = new Object();
- SettingsState settingsState = new SettingsState(
- InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
- SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
-
- Map<String, AconfigdFlagInfo> flags = new HashMap<>();
- String bulkSyncMarker = "aconfigd_marker/bulk_synced";
- String bulkSyncCounter =
- "core_experiments_team_internal/" +
- "BulkSyncTriggerCounterFlag__bulk_sync_trigger_counter";
- synchronized (lock) {
- settingsState.insertSettingLocked("aconfigd_marker/bulk_synced",
- "true", null, false, "aconfig");
-
- // when aconfigd is off, should change the marker to false
- ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertNull(requests);
- String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("0", value);
-
- // marker started with false value, after call, it should remain false
- requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertNull(requests);
- value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("0", value);
-
- // won't sync
- settingsState.insertSettingLocked(bulkSyncMarker, "0", null, false, "aconfig");
- settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false,
- "com.google.android.platform.core_experiments_team_internal");
- requests = settingsState.handleBulkSyncToNewStorage(flags);
- assertNull(requests);
- value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
- assertEquals("0", value);
- }
- }
-
@Test
public void testGetAllAconfigFlagsFromSettings() throws Exception {
final Object lock = new Object();
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp
index 0ff856e..1d74774c 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp
+++ b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp
@@ -5,7 +5,7 @@
aconfig_declarations {
name: "com_android_a11y_menu_flags",
package: "com.android.systemui.accessibility.accessibilitymenu",
- container: "system",
+ container: "system_ext",
srcs: [
"accessibility.aconfig",
],
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
index 6d79011..bdf6d42 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
@@ -1,5 +1,5 @@
package: "com.android.systemui.accessibility.accessibilitymenu"
-container: "system"
+container: "system_ext"
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
index d0c5e7a..49df169 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
@@ -157,7 +157,7 @@
if (
(it.arguments[0] as Intent).`package` == CAST_TO_OTHER_DEVICES_PACKAGE
) {
- emptyList()
+ emptyList<ResolveInfo>()
} else {
listOf(mock<ResolveInfo>())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
index 16061df..8a5797b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
@@ -63,7 +63,7 @@
doAnswer {
// See Utils.isHeadlessRemoteDisplayProvider
if ((it.arguments[0] as Intent).`package` == HEADLESS_REMOTE_PACKAGE) {
- emptyList()
+ emptyList<ResolveInfo>()
} else {
listOf(mock<ResolveInfo>())
}
diff --git a/packages/Vcn/framework-b/framework-vcn-jarjar-rules.txt b/packages/Vcn/framework-b/framework-vcn-jarjar-rules.txt
index 7e27b24..33287b7 100644
--- a/packages/Vcn/framework-b/framework-vcn-jarjar-rules.txt
+++ b/packages/Vcn/framework-b/framework-vcn-jarjar-rules.txt
@@ -1,2 +1,3 @@
rule android.net.vcn.persistablebundleutils.** android.net.connectivity.android.net.vcn.persistablebundleutils.@1
-rule android.net.vcn.util.** android.net.connectivity.android.net.vcn.util.@1
\ No newline at end of file
+rule android.net.vcn.util.** android.net.connectivity.android.net.vcn.util.@1
+rule android.util.IndentingPrintWriter android.net.connectivity.android.util.IndentingPrintWriter
\ No newline at end of file
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 8e99842..adbb3af 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -175,9 +175,9 @@
}
java_device_for_host {
- name: "ravenwood-junit-impl-for-ravenizer",
+ name: "ravenwood-junit-for-ravenizer",
libs: [
- "ravenwood-junit-impl",
+ "ravenwood-junit",
],
visibility: [":__subpackages__"],
}
diff --git a/ravenwood/tools/ravenizer/Android.bp b/ravenwood/tools/ravenizer/Android.bp
index 2892d07..a52a04b 100644
--- a/ravenwood/tools/ravenizer/Android.bp
+++ b/ravenwood/tools/ravenizer/Android.bp
@@ -19,7 +19,7 @@
"ow2-asm-tree",
"ow2-asm-util",
"junit",
- "ravenwood-junit-impl-for-ravenizer",
+ "ravenwood-junit-for-ravenizer",
],
visibility: ["//visibility:public"],
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 8d8064f..ccc0a256 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -113,6 +113,7 @@
DeviceConfig.NAMESPACE_LMKD_NATIVE,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
DeviceConfig.NAMESPACE_MGLRU_NATIVE,
+ DeviceConfig.NAMESPACE_MMD_NATIVE,
DeviceConfig.NAMESPACE_NETD_NATIVE,
DeviceConfig.NAMESPACE_NNAPI_NATIVE,
DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index 7eeec32..f13bfac 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -77,6 +77,7 @@
* This is for verifying the UID report flow.
*/
private static final boolean VALIDATE_UID_STATES = true;
+ @GuardedBy("mLock")
private final ActiveUids mValidateUids;
UidObserverController(@NonNull Handler handler) {
@@ -282,31 +283,30 @@
}
mUidObservers.finishBroadcast();
- if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) {
- for (int j = 0; j < numUidChanges; ++j) {
- final ChangeRecord item = mActiveUidChanges[j];
- if ((item.change & UidRecord.CHANGE_GONE) != 0) {
- mValidateUids.remove(item.uid);
- } else {
- UidRecord validateUid = mValidateUids.get(item.uid);
- if (validateUid == null) {
- validateUid = new UidRecord(item.uid, null);
- mValidateUids.put(item.uid, validateUid);
+ synchronized (mLock) {
+ if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) {
+ for (int j = 0; j < numUidChanges; ++j) {
+ final ChangeRecord item = mActiveUidChanges[j];
+ if ((item.change & UidRecord.CHANGE_GONE) != 0) {
+ mValidateUids.remove(item.uid);
+ } else {
+ UidRecord validateUid = mValidateUids.get(item.uid);
+ if (validateUid == null) {
+ validateUid = new UidRecord(item.uid, null);
+ mValidateUids.put(item.uid, validateUid);
+ }
+ if ((item.change & UidRecord.CHANGE_IDLE) != 0) {
+ validateUid.setIdle(true);
+ } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) {
+ validateUid.setIdle(false);
+ }
+ validateUid.setSetProcState(item.procState);
+ validateUid.setCurProcState(item.procState);
+ validateUid.setSetCapability(item.capability);
+ validateUid.setCurCapability(item.capability);
}
- if ((item.change & UidRecord.CHANGE_IDLE) != 0) {
- validateUid.setIdle(true);
- } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) {
- validateUid.setIdle(false);
- }
- validateUid.setSetProcState(item.procState);
- validateUid.setCurProcState(item.procState);
- validateUid.setSetCapability(item.capability);
- validateUid.setCurCapability(item.capability);
}
}
- }
-
- synchronized (mLock) {
for (int j = 0; j < numUidChanges; j++) {
final ChangeRecord changeRecord = mActiveUidChanges[j];
changeRecord.isPending = false;
@@ -433,7 +433,9 @@
}
UidRecord getValidateUidRecord(int uid) {
- return mValidateUids.get(uid);
+ synchronized (mLock) {
+ return mValidateUids.get(uid);
+ }
}
void dump(@NonNull PrintWriter pw, @Nullable String dumpPackage) {
@@ -488,12 +490,16 @@
boolean dumpValidateUids(@NonNull PrintWriter pw, @Nullable String dumpPackage, int dumpAppId,
@NonNull String header, boolean needSep) {
- return mValidateUids.dump(pw, dumpPackage, dumpAppId, header, needSep);
+ synchronized (mLock) {
+ return mValidateUids.dump(pw, dumpPackage, dumpAppId, header, needSep);
+ }
}
void dumpValidateUidsProto(@NonNull ProtoOutputStream proto, @Nullable String dumpPackage,
int dumpAppId, long fieldId) {
- mValidateUids.dumpProto(proto, dumpPackage, dumpAppId, fieldId);
+ synchronized (mLock) {
+ mValidateUids.dumpProto(proto, dumpPackage, dumpAppId, fieldId);
+ }
}
static final class ChangeRecord {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5b9bab7..b09a192 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -12506,10 +12506,10 @@
int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
if (intent.getBooleanExtra(EXTRA_REPLACING, false) ||
intent.getBooleanExtra(EXTRA_ARCHIVAL, false)) return;
- if (action.equals(ACTION_PACKAGE_ADDED)) {
+ if (ACTION_PACKAGE_ADDED.equals(action)) {
audioserverExecutor.execute(() ->
provider.onModifyPackageState(uid, pkgName, false /* isRemoved */));
- } else if (action.equals(ACTION_PACKAGE_REMOVED)) {
+ } else if (ACTION_PACKAGE_REMOVED.equals(action)) {
audioserverExecutor.execute(() ->
provider.onModifyPackageState(uid, pkgName, true /* isRemoved */));
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 908f51b..ccac969 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1511,10 +1511,13 @@
getUiState(displayId).setImeWindowState(vis, backDisposition, showImeSwitcher);
mHandler.post(() -> {
- if (mBar == null) return;
- try {
- mBar.setImeWindowStatus(displayId, vis, backDisposition, showImeSwitcher);
- } catch (RemoteException ex) { }
+ IStatusBar bar = mBar;
+ if (bar != null) {
+ try {
+ bar.setImeWindowStatus(displayId, vis, backDisposition, showImeSwitcher);
+ } catch (RemoteException ex) {
+ }
+ }
});
}
}
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
index 2dff392..2592612 100644
--- a/services/usb/OWNERS
+++ b/services/usb/OWNERS
@@ -1,9 +1,9 @@
-anothermark@google.com
+vmartensson@google.com
+nkapron@google.com
febinthattil@google.com
-aprasath@google.com
+shubhankarm@google.com
badhri@google.com
elaurent@google.com
albertccwang@google.com
jameswei@google.com
howardyen@google.com
-kumarashishg@google.com
\ No newline at end of file
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index af753e5..b62843c 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -19,6 +19,7 @@
import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
+import com.google.android.lint.multiuser.PendingIntentGetActivityDetector
import com.google.android.lint.parcel.SaferParcelChecker
import com.google.auto.service.AutoService
@@ -40,6 +41,7 @@
PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE,
PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD,
FeatureAutomotiveDetector.ISSUE,
+ PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY,
)
override val api: Int
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt
new file mode 100644
index 0000000..b9f22eb
--- /dev/null
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint.multiuser
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import java.util.EnumSet
+import org.jetbrains.uast.UCallExpression
+
+/**
+ * Detector for flagging potential multiuser issues in `PendingIntent.getActivity()` calls.
+ *
+ * This detector checks for calls to `PendingIntent#getActivity()` and
+ * reports a warning if such a call is found, suggesting that the
+ * default user 0 context might not be the right one.
+ */
+class PendingIntentGetActivityDetector : Detector(), SourceCodeScanner {
+
+ companion object {
+
+ val description = """Flags potential multiuser issue in PendingIntent.getActivity() calls."""
+
+ val EXPLANATION =
+ """
+ **Problem:**
+
+ Calling `PendingIntent.getActivity()` in the `system_server` often accidentally uses the user 0 context. Moreover, since there's no explicit user parameter in the `getActivity` method, it can be hard to tell which user the `PendingIntent` activity is associated with, making the code error-prone and less readable.
+
+ **Solution:**
+
+ Always use the user aware methods to refer the correct user context. You can achieve this by:
+
+ * **Using `PendingIntent.getActivityAsUser(...)`:** This API allows you to explicitly specify the user for the activity.
+
+ ```java
+ PendingIntent.getActivityAsUser(
+ mContext, /*requestCode=*/0, intent,
+ PendingIntent.FLAG_IMMUTABLE, /*options=*/null,
+ UserHandle.of(mUserId));
+ ```
+
+ **When to Ignore this Warning:**
+
+ You can safely ignore this warning if you are certain that:
+
+ * You've confirmed that the `PendingIntent` activity you're targeting is the correct one and is **rightly** associated with the context parameter passed into the `PendingIntent.getActivity` method.
+
+ **Note:** If you are unsure about the user context, it's best to err on the side of caution and explicitly specify the user using the method specified above.
+
+ **For any further questions, please reach out to go/multiuser-help.**
+ """.trimIndent()
+
+ val ISSUE_PENDING_INTENT_GET_ACTIVITY: Issue =
+ Issue.create(
+ id = "PendingIntent#getActivity",
+ briefDescription = description,
+ explanation = EXPLANATION,
+ category = Category.SECURITY,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(
+ PendingIntentGetActivityDetector::class.java,
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES),
+ ),
+ )
+ }
+
+ override fun getApplicableMethodNames() = listOf("getActivity")
+
+ override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ // Check if the method call is PendingIntent.getActivity
+ if (
+ context.evaluator.isMemberInClass(method, "android.app.PendingIntent") &&
+ method.name == "getActivity"
+ ) {
+ context.report(
+ ISSUE_PENDING_INTENT_GET_ACTIVITY,
+ node,
+ context.getLocation(node),
+ "Using `PendingIntent.getActivity(...)` might not be multiuser-aware. " +
+ "Consider using the user aware method `PendingIntent.getActivityAsUser(...)`.",
+ )
+ }
+ }
+}
diff --git a/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt
new file mode 100644
index 0000000..4010550
--- /dev/null
+++ b/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.lint.multiuser
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class PendingIntentGetActivityDetectorTest : LintDetectorTest() {
+
+ override fun getDetector(): Detector = PendingIntentGetActivityDetector()
+
+ override fun getIssues(): List<Issue> =
+ listOf(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY)
+
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+ fun testPendingIntentGetActivity() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+
+ import android.app.PendingIntent;
+ import android.content.Context;
+ import android.content.Intent;
+
+ public class TestClass {
+ private Context mContext;
+
+ public void testMethod(Intent intent) {
+ PendingIntent.getActivity(
+ mContext, /*requestCode=*/0, intent,
+ PendingIntent.FLAG_IMMUTABLE, /*options=*/null
+ );
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs,
+ )
+ .issues(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY)
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:11: Warning: Using PendingIntent.getActivity(...) might not be multiuser-aware. Consider using the user aware method PendingIntent.getActivityAsUser(...). [PendingIntent#getActivity]
+ PendingIntent.getActivity(
+ ^
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ fun testPendingIntentGetActivityAsUser() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+
+ import android.app.PendingIntent;
+ import android.content.Context;
+ import android.content.Intent;
+ import android.os.UserHandle;
+
+ public class TestClass {
+ private Context mContext;
+
+ public void testMethod(Intent intent) {
+ PendingIntent.getActivityAsUser(
+ mContext, /*requestCode=*/0, intent,
+ 0, /*options=*/null,
+ UserHandle.CURRENT
+ );
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs,
+ )
+ .issues(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY)
+ .run()
+ .expectClean()
+ }
+
+ private val pendingIntentStub: TestFile =
+ java(
+ """
+ package android.app;
+
+ import android.content.Context;
+ import android.content.Intent;
+ import android.os.UserHandle;
+
+ public class PendingIntent {
+ public static boolean getActivity(Context context, int requestCode, Intent intent, int flags) {
+ return true;
+ }
+
+ public static boolean getActivityAsUser(
+ Context context,
+ int requestCode,
+ Intent intent,
+ int flags,
+ UserHandle userHandle
+ ) {
+ return true;
+ }
+ }
+ """
+ )
+
+ private val contxtStub: TestFile =
+ java(
+ """
+ package android.content;
+
+ import android.os.UserHandle;
+
+ public class Context {
+
+ public Context createContextAsUser(UserHandle userHandle, int flags) {
+ return this;
+ }
+ }
+
+ """
+ )
+
+ private val userHandleStub: TestFile =
+ java(
+ """
+ package android.os;
+
+ public class UserHandle {
+
+ }
+
+ """
+ )
+
+ private val intentStub: TestFile =
+ java(
+ """
+ package android.content;
+
+ public class Intent {
+
+ }
+ """
+ )
+
+ private val stubs = arrayOf(pendingIntentStub, contxtStub, userHandleStub, intentStub)
+}