Merge "Attempt to de-flake tests."
diff --git a/Android.bp b/Android.bp
index 1ee7405..6288940 100644
--- a/Android.bp
+++ b/Android.bp
@@ -69,7 +69,6 @@
"core/java/android/app/ITaskStackListener.aidl",
"core/java/android/app/IBackupAgent.aidl",
"core/java/android/app/IEphemeralResolver.aidl",
- "core/java/android/app/IInputForwarder.aidl",
"core/java/android/app/IInstantAppResolver.aidl",
"core/java/android/app/IInstrumentationWatcher.aidl",
"core/java/android/app/INotificationManager.aidl",
diff --git a/api/TEST_MAPPING b/api/TEST_MAPPING
index 8a676e9..2cdf54b 100644
--- a/api/TEST_MAPPING
+++ b/api/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "CtsCurrentApiSignatureTestCases"
+ },
+ {
+ "name": "GtsUnofficialApisUsageTestCases"
}
]
}
diff --git a/api/current.txt b/api/current.txt
index fe52f3a..1c60efa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9348,25 +9348,7 @@
field public static final android.os.Parcelable.Creator<android.content.ComponentName> CREATOR;
}
- public interface ContentInterface {
- method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
- method public int bulkInsert(@NonNull android.net.Uri, @NonNull android.content.ContentValues[]) throws android.os.RemoteException;
- method @Nullable public android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle) throws android.os.RemoteException;
- method @Nullable public android.net.Uri canonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
- method public int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
- method @Nullable public String[] getStreamTypes(@NonNull android.net.Uri, @NonNull String) throws android.os.RemoteException;
- method @Nullable public String getType(@NonNull android.net.Uri) throws android.os.RemoteException;
- method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues) throws android.os.RemoteException;
- method @Nullable public android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
- method @Nullable public android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
- method @Nullable public android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
- method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
- method public boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
- method @Nullable public android.net.Uri uncanonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
- method public int update(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
- }
-
- public abstract class ContentProvider implements android.content.ComponentCallbacks2 android.content.ContentInterface {
+ public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
ctor public ContentProvider();
method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
@@ -9419,7 +9401,7 @@
method public void writeDataToPipe(@NonNull android.os.ParcelFileDescriptor, @NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable T);
}
- public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(@NonNull android.net.Uri, @NonNull android.content.ContentValues[]) throws android.os.RemoteException;
@@ -9502,8 +9484,8 @@
method public void setKeepUpdated(boolean);
}
- public abstract class ContentResolver implements android.content.ContentInterface {
- ctor public ContentResolver(android.content.Context);
+ public abstract class ContentResolver {
+ ctor public ContentResolver(@Nullable android.content.Context);
method @Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull android.net.Uri);
method @Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull String);
method @Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull android.net.Uri);
@@ -9568,6 +9550,8 @@
method public final void unregisterContentObserver(@NonNull android.database.ContentObserver);
method public final int update(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
method public static void validateSyncExtrasBundle(android.os.Bundle);
+ method public static android.content.ContentResolver wrap(@NonNull android.content.ContentProvider);
+ method public static android.content.ContentResolver wrap(@NonNull android.content.ContentProviderClient);
field public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
field public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
field public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
@@ -38171,38 +38155,26 @@
method public static android.net.Uri buildRootsUri(String);
method public static android.net.Uri buildSearchDocumentsUri(String, String, String);
method public static android.net.Uri buildTreeDocumentUri(String, String);
- method public static android.net.Uri copyDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method @Deprecated public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, String, String) throws java.io.FileNotFoundException;
- method @Deprecated public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
- method public static android.content.IntentSender createWebLinkIntent(android.content.ContentInterface, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
- method @Deprecated public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
- method public static boolean deleteDocument(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
- method @Deprecated public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static void ejectRoot(android.content.ContentInterface, android.net.Uri);
- method @Deprecated public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
- method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
- method @Deprecated public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+ method @Nullable public static android.net.Uri copyDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+ method @Nullable public static android.net.Uri createDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull String, @NonNull String) throws java.io.FileNotFoundException;
+ method @Nullable public static android.content.IntentSender createWebLinkIntent(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
+ method public static boolean deleteDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+ method public static void ejectRoot(@NonNull android.content.ContentResolver, @NonNull android.net.Uri);
+ method @Nullable public static android.provider.DocumentsContract.Path findDocumentPath(@NonNull android.content.ContentResolver, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
method public static String getDocumentId(android.net.Uri);
- method @Nullable public static android.os.Bundle getDocumentMetadata(@NonNull android.content.ContentInterface, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
- method @Deprecated public static android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentInterface, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
- method @Deprecated public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+ method @Nullable public static android.os.Bundle getDocumentMetadata(@NonNull android.content.ContentResolver, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+ method @Nullable public static android.graphics.Bitmap getDocumentThumbnail(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.graphics.Point, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public static String getRootId(android.net.Uri);
method public static String getSearchDocumentsQuery(android.net.Uri);
method public static String getTreeDocumentId(android.net.Uri);
- method public static boolean isChildDocument(@NonNull android.content.ContentInterface, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
- method @Deprecated public static boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static boolean isChildDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
method public static boolean isDocumentUri(android.content.Context, @Nullable android.net.Uri);
method public static boolean isRootUri(@NonNull android.content.Context, @Nullable android.net.Uri);
method public static boolean isRootsUri(@NonNull android.content.Context, @Nullable android.net.Uri);
method public static boolean isTreeUri(android.net.Uri);
- method public static android.net.Uri moveDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method @Deprecated public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static boolean removeDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method @Deprecated public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, String) throws java.io.FileNotFoundException;
- method @Deprecated public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+ method @Nullable public static android.net.Uri moveDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+ method public static boolean removeDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+ method @Nullable public static android.net.Uri renameDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
field public static final String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS";
field public static final String EXTRA_ERROR = "error";
field public static final String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
diff --git a/api/system-current.txt b/api/system-current.txt
index 8296eee..128ee99 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -304,7 +304,7 @@
}
public class AppOpsManager {
- method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(int, @Nullable String, @Nullable String[], long, long, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+ method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static String[] getOpStrs();
method @Deprecated @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, String, int[]);
method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
@@ -394,6 +394,17 @@
field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
}
+ public static final class AppOpsManager.HistoricalOpsRequest {
+ }
+
+ public static final class AppOpsManager.HistoricalOpsRequest.Builder {
+ ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
+ }
+
public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
@@ -1284,11 +1295,11 @@
package android.content {
- public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
}
- public abstract class ContentResolver implements android.content.ContentInterface {
+ public abstract class ContentResolver {
method public android.os.Bundle getCache(android.net.Uri);
method public android.graphics.drawable.Drawable getTypeDrawable(String);
method public void putCache(android.net.Uri, android.os.Bundle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 16098c1..01678b1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -101,8 +101,8 @@
public class AppOpsManager {
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void addHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOps);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void clearHistory();
- method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(int, @Nullable String, @Nullable String[], long, long, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
- method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOpsFromDiskRaw(int, @Nullable String, @Nullable String[], long, long, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+ method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+ method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static int getNumOps();
method public static String[] getOpStrs();
method public boolean isOperationActive(int, int, String);
@@ -206,6 +206,17 @@
field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
}
+ public static final class AppOpsManager.HistoricalOpsRequest {
+ }
+
+ public static final class AppOpsManager.HistoricalOpsRequest.Builder {
+ ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
+ }
+
public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
@@ -472,11 +483,11 @@
package android.content {
- public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
}
- public abstract class ContentResolver implements android.content.ContentInterface {
+ public abstract class ContentResolver {
method public static String[] getSyncAdapterPackagesForAuthorityAsUser(String, int);
}
diff --git a/config/hiddenapi-force-blacklist.txt b/config/hiddenapi-force-blacklist.txt
index dca3b52..b328f2a 100644
--- a/config/hiddenapi-force-blacklist.txt
+++ b/config/hiddenapi-force-blacklist.txt
@@ -1,4 +1,6 @@
Ldalvik/system/VMRuntime;->setHiddenApiExemptions([Ljava/lang/String;)V
+Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V
+Ldalvik/system/VMRuntime;->setTargetSdkVersionNative(I)V
Ljava/lang/invoke/MethodHandles$Lookup;->IMPL_LOOKUP:Ljava/lang/invoke/MethodHandles$Lookup;
Ljava/lang/invoke/VarHandle;->acquireFence()V
Ljava/lang/invoke/VarHandle;->compareAndExchange([Ljava/lang/Object;)Ljava/lang/Object;
diff --git a/config/hiddenapi-greylist-max-o.txt b/config/hiddenapi-greylist-max-o.txt
index 4b6cc0e..d9c1cd0 100644
--- a/config/hiddenapi-greylist-max-o.txt
+++ b/config/hiddenapi-greylist-max-o.txt
@@ -109777,7 +109777,6 @@
Ldalvik/system/VMRuntime;->setNonSdkApiUsageConsumer(Ljava/util/function/Consumer;)V
Ldalvik/system/VMRuntime;->setProcessPackageName(Ljava/lang/String;)V
Ldalvik/system/VMRuntime;->setSystemDaemonThreadPriority()V
-Ldalvik/system/VMRuntime;->setTargetSdkVersionNative(I)V
Ldalvik/system/VMRuntime;->startHeapTaskProcessor()V
Ldalvik/system/VMRuntime;->startJitCompilation()V
Ldalvik/system/VMRuntime;->stopHeapTaskProcessor()V
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index dc2ed4c..a836e8e 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -170,7 +170,6 @@
Landroid/app/IAssistDataReceiver$Stub;-><init>()V
Landroid/app/IAssistDataReceiver;->onHandleAssistData(Landroid/os/Bundle;)V
Landroid/app/IAssistDataReceiver;->onHandleAssistScreenshot(Landroid/graphics/Bitmap;)V
-Landroid/app/IInputForwarder;->forwardEvent(Landroid/view/InputEvent;)Z
Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
Landroid/app/IInstrumentationWatcher;->instrumentationStatus(Landroid/content/ComponentName;ILandroid/os/Bundle;)V
Landroid/app/INotificationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 69c450c..7d828d8 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -259,10 +259,11 @@
public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
long duration, String tag);
- public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent,
- String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
- boolean sticky, int userId, boolean allowBackgroundActivityStarts);
+ public abstract int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+ int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
+ int resultCode, String resultData, Bundle resultExtras, String requiredPermission,
+ Bundle bOptions, boolean serialized, boolean sticky, int userId,
+ boolean allowBackgroundActivityStarts);
public abstract ComponentName startServiceInPackage(int uid, Intent service,
String resolvedType, boolean fgRequired, String callingPackage, int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index ce71998..bcbeb22 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -291,6 +291,9 @@
/** Send current location and size to the WM to set tap exclude region for this view. */
private void updateLocation() {
+ if (!isAttachedToWindow()) {
+ return;
+ }
try {
getLocationInWindow(mLocationInWindow);
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
@@ -429,6 +432,9 @@
/** Report to server that tap exclude region on hosting display should be cleared. */
private void cleanTapExcludeRegion() {
+ if (!isAttachedToWindow()) {
+ return;
+ }
// Update tap exclude region with an empty rect to clean the state on server.
try {
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 13eec58..040ad06 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -46,6 +46,8 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+
+import com.android.internal.annotations.Immutable;
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsNotedCallback;
@@ -2210,6 +2212,115 @@
}
/**
+ * Request for getting historical app op usage. The request acts
+ * as a filtering criteria when querying historical op usage.
+ *
+ * @hide
+ */
+ @Immutable
+ @TestApi
+ @SystemApi
+ public static final class HistoricalOpsRequest {
+ private final int mUid;
+ private final @Nullable String mPackageName;
+ private final @Nullable List<String> mOpNames;
+ private final long mBeginTimeMillis;
+ private final long mEndTimeMillis;
+
+ private HistoricalOpsRequest(int uid, @Nullable String packageName,
+ @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis) {
+ mUid = uid;
+ mPackageName = packageName;
+ mOpNames = opNames;
+ mBeginTimeMillis = beginTimeMillis;
+ mEndTimeMillis = endTimeMillis;
+ }
+
+ /**
+ * Builder for creating a {@link HistoricalOpsRequest}.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final class Builder {
+ private int mUid = Process.INVALID_UID;
+ private @Nullable String mPackageName;
+ private @Nullable List<String> mOpNames;
+ private final long mBeginTimeMillis;
+ private final long mEndTimeMillis;
+
+ /**
+ * Creates a new builder.
+ *
+ * @param beginTimeMillis The beginning of the interval in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
+ * negative.
+ * @param endTimeMillis The end of the interval in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
+ * {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
+ * history including ops that happen while this call is in flight.
+ */
+ public Builder(long beginTimeMillis, long endTimeMillis) {
+ Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
+ "beginTimeMillis must be non negative and lesser than endTimeMillis");
+ mBeginTimeMillis = beginTimeMillis;
+ mEndTimeMillis = endTimeMillis;
+ }
+
+ /**
+ * Sets the UID to query for.
+ *
+ * @param uid The uid. Pass {@link android.os.Process#INVALID_UID} for any uid.
+ * @return This builder.
+ */
+ public @NonNull Builder setUid(int uid) {
+ Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+ "uid must be " + Process.INVALID_UID + " or non negative");
+ mUid = uid;
+ return this;
+ }
+
+ /**
+ * Sets the package to query for.
+ *
+ * @param packageName The package name. <code>Null</code> for any package.
+ * @return This builder.
+ */
+ public @NonNull Builder setPackageName(@Nullable String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ /**
+ * Sets the op names to query for.
+ *
+ * @param opNames The op names. <code>Null</code> for any op.
+ * @return This builder.
+ */
+ public @NonNull Builder setOpNames(@Nullable List<String> opNames) {
+ if (opNames != null) {
+ final int opCount = opNames.size();
+ for (int i = 0; i < opCount; i++) {
+ Preconditions.checkArgument(AppOpsManager.strOpToOp(
+ opNames.get(i)) != AppOpsManager.OP_NONE);
+ }
+ }
+ mOpNames = opNames;
+ return this;
+ }
+
+ /**
+ * @return a new {@link HistoricalOpsRequest}.
+ */
+ public @NonNull HistoricalOpsRequest build() {
+ return new HistoricalOpsRequest(mUid, mPackageName, mOpNames,
+ mBeginTimeMillis, mEndTimeMillis);
+ }
+ }
+ }
+
+ /**
* This class represents historical app op state of all UIDs for a given time interval.
*
* @hide
@@ -3671,26 +3782,7 @@
/**
* Retrieve historical app op stats for a period.
*
- * <p>Historical data can be obtained
- * for a specific package by specifying the <code>packageName</code> argument,
- * for a specific UID if specifying the <code>uid</code> argument, for a
- * specific package in a UID by specifying the <code>packageName</code>
- * and the <code>uid</code> arguments, for all packages by passing
- * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
- * <code>uid</code> and <code>packageName</code> arguments, respectively.
- * Similarly, you can specify the <code>opNames</code> argument to get
- * data only for these ops or <code>null</code> for all ops.
- *
- * @param uid The UID to query for.
- * @param packageName The package to query for.
- * @param beginTimeMillis The beginning of the interval in milliseconds since
- * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
- * negative.
- * @param endTimeMillis The end of the interval in milliseconds since
- * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
- * {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
- * history including ops that happen while this call is in flight.
- * @param opNames The ops to query for. Pass {@code null} for all ops.
+ * @param request A request object describing the data being queried for.
* @param executor Executor on which to run the callback. If <code>null</code>
* the callback is executed on the default executor running on the main thread.
* @param callback Callback on which to deliver the result.
@@ -3702,13 +3794,13 @@
@TestApi
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
- public void getHistoricalOps(int uid, @Nullable String packageName,
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ public void getHistoricalOps(@NonNull HistoricalOpsRequest request,
@NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
Preconditions.checkNotNull(executor, "executor cannot be null");
Preconditions.checkNotNull(callback, "callback cannot be null");
try {
- mService.getHistoricalOps(uid, packageName, opNames, beginTimeMillis, endTimeMillis,
+ mService.getHistoricalOps(request.mUid, request.mPackageName, request.mOpNames,
+ request.mBeginTimeMillis, request.mEndTimeMillis,
new RemoteCallback((result) -> {
final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
final long identity = Binder.clearCallingIdentity();
@@ -3725,29 +3817,12 @@
/**
* Retrieve historical app op stats for a period.
- *
- * <p>Historical data can be obtained
- * for a specific package by specifying the <code>packageName</code> argument,
- * for a specific UID if specifying the <code>uid</code> argument, for a
- * specific package in a UID by specifying the <code>packageName</code>
- * and the <code>uid</code> arguments, for all packages by passing
- * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
- * <code>uid</code> and <code>packageName</code> arguments, respectively.
- * Similarly, you can specify the <code>opNames</code> argument to get
- * data only for these ops or <code>null</code> for all ops.
* <p>
* This method queries only the on disk state and the returned ops are raw,
* which is their times are relative to the history start as opposed to the
* epoch start.
*
- * @param uid The UID to query for.
- * @param packageName The package to query for.
- * @param beginTimeMillis The beginning of the interval in milliseconds since
- * history start. History time grows as one goes into the past.
- * @param endTimeMillis The end of the interval in milliseconds since
- * history start. History time grows as one goes into the past. Must be after
- * {@code beginTimeMillis}.
- * @param opNames The ops to query for. Pass {@code null} for all ops.
+ * @param request A request object describing the data being queried for.
* @param executor Executor on which to run the callback. If <code>null</code>
* the callback is executed on the default executor running on the main thread.
* @param callback Callback on which to deliver the result.
@@ -3758,15 +3833,15 @@
*/
@TestApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
- public void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName,
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ public void getHistoricalOpsFromDiskRaw(@NonNull HistoricalOpsRequest request,
@Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
Preconditions.checkNotNull(executor, "executor cannot be null");
Preconditions.checkNotNull(callback, "callback cannot be null");
try {
- mService.getHistoricalOpsFromDiskRaw(uid, packageName, opNames, beginTimeMillis,
- endTimeMillis, new RemoteCallback((result) -> {
- final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+ mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
+ request.mOpNames, request.mBeginTimeMillis, request.mEndTimeMillis,
+ new RemoteCallback((result) -> {
+ final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
final long identity = Binder.clearCallingIdentity();
try {
executor.execute(() -> callback.accept(ops));
diff --git a/core/java/android/app/IInputForwarder.aidl b/core/java/android/app/IInputForwarder.aidl
deleted file mode 100644
index d6be63e..0000000
--- a/core/java/android/app/IInputForwarder.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2017, 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 android.app;
-
-import android.view.InputEvent;
-
-/**
- * Forwards input events into owned activity container, used in {@link android.app.ActivityView}.
- * To forward input to other apps {@link android.Manifest.permission.INJECT_EVENTS} permission is
- * required.
- * @hide
- */
-interface IInputForwarder {
- boolean forwardEvent(in InputEvent event);
-}
\ No newline at end of file
diff --git a/core/java/android/app/admin/TEST_MAPPING b/core/java/android/app/admin/TEST_MAPPING
new file mode 100644
index 0000000..8f88c22
--- /dev/null
+++ b/core/java/android/app/admin/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/services/devicepolicy"
+ }
+ ]
+}
diff --git a/core/java/android/content/ContentInterface.java b/core/java/android/content/ContentInterface.java
index 3d732eb..d41d8d9 100644
--- a/core/java/android/content/ContentInterface.java
+++ b/core/java/android/content/ContentInterface.java
@@ -36,6 +36,8 @@
* These methods have been extracted into a general interface so that APIs can
* be flexible in accepting either a {@link ContentProvider}, a
* {@link ContentResolver}, or a {@link ContentProviderClient}.
+ *
+ * @hide
*/
public interface ContentInterface {
public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index f138d39..e06322df 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -134,7 +134,7 @@
private boolean mNoPerms;
private boolean mSingleUser;
- private final ThreadLocal<String> mCallingPackage = new ThreadLocal<>();
+ private ThreadLocal<String> mCallingPackage;
private Transport mTransport = new Transport();
@@ -2034,6 +2034,7 @@
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
+ mCallingPackage = new ThreadLocal<>();
/*
* Only allow it to be set once, so after the content service gives
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7672ccf..bbfa5cc 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -609,10 +609,60 @@
private static final int SLOW_THRESHOLD_MILLIS = 500;
private final Random mRandom = new Random(); // guarded by itself
- public ContentResolver(Context context) {
+ public ContentResolver(@Nullable Context context) {
+ this(context, null);
+ }
+
+ /** {@hide} */
+ public ContentResolver(@Nullable Context context, @Nullable ContentInterface wrapped) {
mContext = context != null ? context : ActivityThread.currentApplication();
mPackageName = mContext.getOpPackageName();
mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ mWrapped = wrapped;
+ }
+
+ /** {@hide} */
+ public static ContentResolver wrap(@NonNull ContentInterface wrapped) {
+ Preconditions.checkNotNull(wrapped);
+
+ return new ContentResolver(null, wrapped) {
+ @Override
+ public void unstableProviderDied(IContentProvider icp) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public boolean releaseUnstableProvider(IContentProvider icp) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public boolean releaseProvider(IContentProvider icp) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ protected IContentProvider acquireUnstableProvider(Context c, String name) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ protected IContentProvider acquireProvider(Context c, String name) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Create a {@link ContentResolver} instance that redirects all its methods
+ * to the given {@link ContentProvider}.
+ */
+ public static ContentResolver wrap(@NonNull ContentProvider wrapped) {
+ return wrap((ContentInterface) wrapped);
+ }
+
+ /**
+ * Create a {@link ContentResolver} instance that redirects all its methods
+ * to the given {@link ContentProviderClient}.
+ */
+ public static ContentResolver wrap(@NonNull ContentProviderClient wrapped) {
+ return wrap((ContentInterface) wrapped);
}
/** @hide */
@@ -660,6 +710,12 @@
public final @Nullable String getType(@NonNull Uri url) {
Preconditions.checkNotNull(url, "url");
+ try {
+ if (mWrapped != null) return mWrapped.getType(url);
+ } catch (RemoteException e) {
+ return null;
+ }
+
// XXX would like to have an acquireExistingUnstableProvider for this.
IContentProvider provider = acquireExistingProvider(url);
if (provider != null) {
@@ -715,6 +771,12 @@
Preconditions.checkNotNull(url, "url");
Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
+ try {
+ if (mWrapped != null) return mWrapped.getStreamTypes(url, mimeTypeFilter);
+ } catch (RemoteException e) {
+ return null;
+ }
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
return null;
@@ -843,6 +905,15 @@
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
+
+ try {
+ if (mWrapped != null) {
+ return mWrapped.query(uri, projection, queryArgs, cancellationSignal);
+ }
+ } catch (RemoteException e) {
+ return null;
+ }
+
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
@@ -942,6 +1013,13 @@
@Override
public final @Nullable Uri canonicalize(@NonNull Uri url) {
Preconditions.checkNotNull(url, "url");
+
+ try {
+ if (mWrapped != null) return mWrapped.canonicalize(url);
+ } catch (RemoteException e) {
+ return null;
+ }
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
return null;
@@ -979,6 +1057,13 @@
@Override
public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
Preconditions.checkNotNull(url, "url");
+
+ try {
+ if (mWrapped != null) return mWrapped.uncanonicalize(url);
+ } catch (RemoteException e) {
+ return null;
+ }
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
return null;
@@ -1015,6 +1100,13 @@
public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(url, "url");
+
+ try {
+ if (mWrapped != null) return mWrapped.refresh(url, args, cancellationSignal);
+ } catch (RemoteException e) {
+ return false;
+ }
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
return false;
@@ -1126,6 +1218,12 @@
@Override
public final @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
@Nullable CancellationSignal signal) throws FileNotFoundException {
+ try {
+ if (mWrapped != null) return mWrapped.openFile(uri, mode, signal);
+ } catch (RemoteException e) {
+ return null;
+ }
+
return openFileDescriptor(uri, mode, signal);
}
@@ -1237,6 +1335,12 @@
@Override
public final @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
@Nullable CancellationSignal signal) throws FileNotFoundException {
+ try {
+ if (mWrapped != null) return mWrapped.openAssetFile(uri, mode, signal);
+ } catch (RemoteException e) {
+ return null;
+ }
+
return openAssetFileDescriptor(uri, mode, signal);
}
@@ -1448,6 +1552,14 @@
public final @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
@NonNull String mimeTypeFilter, @Nullable Bundle opts,
@Nullable CancellationSignal signal) throws FileNotFoundException {
+ try {
+ if (mWrapped != null) {
+ return mWrapped.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
+ }
+ } catch (RemoteException e) {
+ return null;
+ }
+
return openTypedAssetFileDescriptor(uri, mimeTypeFilter, opts, signal);
}
@@ -1664,6 +1776,13 @@
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
@Nullable ContentValues values) {
Preconditions.checkNotNull(url, "url");
+
+ try {
+ if (mWrapped != null) return mWrapped.insert(url, values);
+ } catch (RemoteException e) {
+ return null;
+ }
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
@@ -1705,6 +1824,13 @@
throws RemoteException, OperationApplicationException {
Preconditions.checkNotNull(authority, "authority");
Preconditions.checkNotNull(operations, "operations");
+
+ try {
+ if (mWrapped != null) return mWrapped.applyBatch(authority, operations);
+ } catch (RemoteException e) {
+ return null;
+ }
+
ContentProviderClient provider = acquireContentProviderClient(authority);
if (provider == null) {
throw new IllegalArgumentException("Unknown authority " + authority);
@@ -1731,6 +1857,13 @@
@NonNull ContentValues[] values) {
Preconditions.checkNotNull(url, "url");
Preconditions.checkNotNull(values, "values");
+
+ try {
+ if (mWrapped != null) return mWrapped.bulkInsert(url, values);
+ } catch (RemoteException e) {
+ return 0;
+ }
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
@@ -1764,6 +1897,13 @@
public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
@Nullable String[] selectionArgs) {
Preconditions.checkNotNull(url, "url");
+
+ try {
+ if (mWrapped != null) return mWrapped.delete(url, where, selectionArgs);
+ } catch (RemoteException e) {
+ return 0;
+ }
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
@@ -1801,6 +1941,13 @@
@Nullable ContentValues values, @Nullable String where,
@Nullable String[] selectionArgs) {
Preconditions.checkNotNull(uri, "uri");
+
+ try {
+ if (mWrapped != null) return mWrapped.update(uri, values, where, selectionArgs);
+ } catch (RemoteException e) {
+ return 0;
+ }
+
IContentProvider provider = acquireProvider(uri);
if (provider == null) {
throw new IllegalArgumentException("Unknown URI " + uri);
@@ -1844,6 +1991,13 @@
@Nullable String arg, @Nullable Bundle extras) {
Preconditions.checkNotNull(authority, "authority");
Preconditions.checkNotNull(method, "method");
+
+ try {
+ if (mWrapped != null) return mWrapped.call(authority, method, arg, extras);
+ } catch (RemoteException e) {
+ return null;
+ }
+
IContentProvider provider = acquireProvider(authority);
if (provider == null) {
throw new IllegalArgumentException("Unknown authority " + authority);
@@ -3193,6 +3347,7 @@
@UnsupportedAppUsage
final String mPackageName;
final int mTargetSdkVersion;
+ final ContentInterface mWrapped;
private static final String TAG = "ContentResolver";
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index f413d7c..0c07a67 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -65,7 +65,8 @@
@SystemApi
public static final int CAPABILITY_NONE = 0x0;
/**
- * The device can properly apply transforms over protected content.
+ * The device can use GPU composition on protected content (layers whose buffers are protected
+ * in the trusted memory zone).
*
* @hide
*/
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 44b653c..8a0a9c7 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -563,7 +563,8 @@
* 0 produces a grayscale image, 1 is normal.
*
* @hide
- * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)}.
+ * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)} instead. The level passed
+ * as a parameter here will be rounded to the nearest hundredth.
*/
@SystemApi
@RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 97868fa..64448fd 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -16,7 +16,6 @@
package android.hardware.input;
-import android.app.IInputForwarder;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.IInputDevicesChangedListener;
@@ -82,7 +81,4 @@
void setCustomPointerIcon(in PointerIcon icon);
void requestPointerCapture(IBinder windowToken, boolean enabled);
-
- /** Create input forwarder to deliver touch events to owned display. */
- IInputForwarder createInputForwarder(int displayId);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index bfb7c58..fec5c34 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -21,7 +21,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
-import android.app.IInputForwarder;
import android.content.Context;
import android.media.AudioAttributes;
import android.os.Binder;
@@ -934,26 +933,6 @@
}
}
-
- /**
- * Create an {@link IInputForwarder} targeted to provided display.
- * {@link android.Manifest.permission.INJECT_EVENTS} permission is required to call this method.
- *
- * @param displayId Id of the target display where input events should be forwarded.
- * Display must exist and must be owned by the caller.
- * @return The forwarder instance.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public IInputForwarder createInputForwarder(int displayId) {
- try {
- return mIm.createInputForwarder(displayId);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
private void populateInputDevicesLocked() {
if (mInputDevicesChangedListener == null) {
final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 5708342..d282967 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1281,8 +1281,9 @@
* @see DocumentsProvider#openDocumentThumbnail(String, Point,
* android.os.CancellationSignal)
*/
- public static Bitmap getDocumentThumbnail(ContentInterface content, Uri documentUri, Point size,
- CancellationSignal signal) throws FileNotFoundException {
+ public static @Nullable Bitmap getDocumentThumbnail(@NonNull ContentResolver content,
+ @NonNull Uri documentUri, @NonNull Point size, @Nullable CancellationSignal signal)
+ throws FileNotFoundException {
try {
return ContentResolver.loadThumbnail(content, documentUri, Point.convert(size), signal,
ImageDecoder.ALLOCATOR_SOFTWARE);
@@ -1295,12 +1296,6 @@
}
}
- @Deprecated
- public static Bitmap getDocumentThumbnail(ContentResolver content, Uri documentUri, Point size,
- CancellationSignal signal) throws FileNotFoundException {
- return getDocumentThumbnail((ContentInterface) content, documentUri, size, signal);
- }
-
/**
* Create a new document with given MIME type and display name.
*
@@ -1309,8 +1304,9 @@
* @param displayName name of new document
* @return newly created document, or {@code null} if failed
*/
- public static Uri createDocument(ContentInterface content, Uri parentDocumentUri,
- String mimeType, String displayName) throws FileNotFoundException {
+ public static @Nullable Uri createDocument(@NonNull ContentResolver content,
+ @NonNull Uri parentDocumentUri, @NonNull String mimeType, @NonNull String displayName)
+ throws FileNotFoundException {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
@@ -1327,12 +1323,6 @@
}
}
- @Deprecated
- public static Uri createDocument(ContentResolver content, Uri parentDocumentUri,
- String mimeType, String displayName) throws FileNotFoundException {
- return createDocument((ContentInterface) content, parentDocumentUri, mimeType, displayName);
- }
-
/**
* Test if a document is descendant (child, grandchild, etc) from the given
* parent.
@@ -1342,7 +1332,7 @@
* @return if given document is a descendant of the given parent.
* @see Root#FLAG_SUPPORTS_IS_CHILD
*/
- public static boolean isChildDocument(@NonNull ContentInterface content,
+ public static boolean isChildDocument(@NonNull ContentResolver content,
@NonNull Uri parentDocumentUri, @NonNull Uri childDocumentUri)
throws FileNotFoundException {
Preconditions.checkNotNull(content, "content can not be null");
@@ -1369,12 +1359,6 @@
}
}
- @Deprecated
- public static boolean isChildDocument(ContentResolver content, Uri parentDocumentUri,
- Uri childDocumentUri) throws FileNotFoundException {
- return isChildDocument((ContentInterface) content, parentDocumentUri, childDocumentUri);
- }
-
/**
* Change the display name of an existing document.
* <p>
@@ -1388,8 +1372,8 @@
* @return the existing or new document after the rename, or {@code null} if
* failed.
*/
- public static Uri renameDocument(ContentInterface content, Uri documentUri,
- String displayName) throws FileNotFoundException {
+ public static @Nullable Uri renameDocument(@NonNull ContentResolver content,
+ @NonNull Uri documentUri, @NonNull String displayName) throws FileNotFoundException {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
@@ -1406,19 +1390,13 @@
}
}
- @Deprecated
- public static Uri renameDocument(ContentResolver content, Uri documentUri,
- String displayName) throws FileNotFoundException {
- return renameDocument((ContentInterface) content, documentUri, displayName);
- }
-
/**
* Delete the given document.
*
* @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE}
* @return if the document was deleted successfully.
*/
- public static boolean deleteDocument(ContentInterface content, Uri documentUri)
+ public static boolean deleteDocument(@NonNull ContentResolver content, @NonNull Uri documentUri)
throws FileNotFoundException {
try {
final Bundle in = new Bundle();
@@ -1434,12 +1412,6 @@
}
}
- @Deprecated
- public static boolean deleteDocument(ContentResolver content, Uri documentUri)
- throws FileNotFoundException {
- return deleteDocument((ContentInterface) content, documentUri);
- }
-
/**
* Copies the given document.
*
@@ -1448,8 +1420,9 @@
* document's copy.
* @return the copied document, or {@code null} if failed.
*/
- public static Uri copyDocument(ContentInterface content, Uri sourceDocumentUri,
- Uri targetParentDocumentUri) throws FileNotFoundException {
+ public static @Nullable Uri copyDocument(@NonNull ContentResolver content,
+ @NonNull Uri sourceDocumentUri, @NonNull Uri targetParentDocumentUri)
+ throws FileNotFoundException {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
@@ -1465,12 +1438,6 @@
}
}
- @Deprecated
- public static Uri copyDocument(ContentResolver content, Uri sourceDocumentUri,
- Uri targetParentDocumentUri) throws FileNotFoundException {
- return copyDocument((ContentInterface) content, sourceDocumentUri, targetParentDocumentUri);
- }
-
/**
* Moves the given document under a new parent.
*
@@ -1480,8 +1447,9 @@
* document.
* @return the moved document, or {@code null} if failed.
*/
- public static Uri moveDocument(ContentInterface content, Uri sourceDocumentUri,
- Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException {
+ public static @Nullable Uri moveDocument(@NonNull ContentResolver content,
+ @NonNull Uri sourceDocumentUri, @NonNull Uri sourceParentDocumentUri,
+ @NonNull Uri targetParentDocumentUri) throws FileNotFoundException {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
@@ -1498,13 +1466,6 @@
}
}
- @Deprecated
- public static Uri moveDocument(ContentResolver content, Uri sourceDocumentUri,
- Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException {
- return moveDocument((ContentInterface) content, sourceDocumentUri, sourceParentDocumentUri,
- targetParentDocumentUri);
- }
-
/**
* Removes the given document from a parent directory.
*
@@ -1515,8 +1476,8 @@
* @param parentDocumentUri parent document of the document to remove.
* @return true if the document was removed successfully.
*/
- public static boolean removeDocument(ContentInterface content, Uri documentUri,
- Uri parentDocumentUri) throws FileNotFoundException {
+ public static boolean removeDocument(@NonNull ContentResolver content, @NonNull Uri documentUri,
+ @NonNull Uri parentDocumentUri) throws FileNotFoundException {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
@@ -1532,34 +1493,23 @@
}
}
- @Deprecated
- public static boolean removeDocument(ContentResolver content, Uri documentUri,
- Uri parentDocumentUri) throws FileNotFoundException {
- return removeDocument((ContentInterface) content, documentUri, parentDocumentUri);
- }
-
/**
* Ejects the given root. It throws {@link IllegalStateException} when ejection failed.
*
* @param rootUri root with {@link Root#FLAG_SUPPORTS_EJECT} to be ejected
*/
- public static void ejectRoot(ContentInterface content, Uri rootUri) {
+ public static void ejectRoot(@NonNull ContentResolver content, @NonNull Uri rootUri) {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, rootUri);
content.call(rootUri.getAuthority(),
METHOD_EJECT_ROOT, null, in);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to eject", e);
}
}
- @Deprecated
- public static void ejectRoot(ContentResolver content, Uri rootUri) {
- ejectRoot((ContentInterface) content, rootUri);
- }
-
/**
* Returns metadata associated with the document. The type of metadata returned
* is specific to the document type. For example the data returned for an image
@@ -1590,7 +1540,7 @@
* @param documentUri a Document URI
* @return a Bundle of Bundles.
*/
- public static @Nullable Bundle getDocumentMetadata(@NonNull ContentInterface content,
+ public static @Nullable Bundle getDocumentMetadata(@NonNull ContentResolver content,
@NonNull Uri documentUri) throws FileNotFoundException {
Preconditions.checkNotNull(content, "content can not be null");
Preconditions.checkNotNull(documentUri, "documentUri can not be null");
@@ -1607,12 +1557,6 @@
}
}
- @Deprecated
- public static Bundle getDocumentMetadata(ContentResolver content, Uri documentUri)
- throws FileNotFoundException {
- return getDocumentMetadata((ContentInterface) content, documentUri);
- }
-
/**
* Finds the canonical path from the top of the document tree.
*
@@ -1626,8 +1570,8 @@
* @return the path of the document, or {@code null} if failed.
* @see DocumentsProvider#findDocumentPath(String, String)
*/
- public static Path findDocumentPath(ContentInterface content, Uri treeUri)
- throws FileNotFoundException {
+ public static @Nullable Path findDocumentPath(@NonNull ContentResolver content,
+ @NonNull Uri treeUri) throws FileNotFoundException {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, treeUri);
@@ -1642,12 +1586,6 @@
}
}
- @Deprecated
- public static Path findDocumentPath(ContentResolver content, Uri treeUri)
- throws FileNotFoundException {
- return findDocumentPath((ContentInterface) content, treeUri);
- }
-
/**
* Creates an intent for obtaining a web link for the specified document.
*
@@ -1699,8 +1637,8 @@
* @see DocumentsProvider#createWebLinkIntent(String, Bundle)
* @see Intent#EXTRA_EMAIL
*/
- public static IntentSender createWebLinkIntent(ContentInterface content, Uri uri,
- Bundle options) throws FileNotFoundException {
+ public static @Nullable IntentSender createWebLinkIntent(@NonNull ContentResolver content,
+ @NonNull Uri uri, @Nullable Bundle options) throws FileNotFoundException {
try {
final Bundle in = new Bundle();
in.putParcelable(DocumentsContract.EXTRA_URI, uri);
@@ -1721,12 +1659,6 @@
}
}
- @Deprecated
- public static IntentSender createWebLinkIntent(ContentResolver content, Uri uri,
- Bundle options) throws FileNotFoundException {
- return createWebLinkIntent((ContentInterface) content, uri, options);
- }
-
/**
* Open the given image for thumbnail purposes, using any embedded EXIF
* thumbnail if available, and providing orientation hints from the parent
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index c4ab91f..8a90cad 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -44,9 +44,9 @@
int checkPackage(int uid, String packageName);
List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
- void getHistoricalOps(int uid, String packageName, in String[] ops, long beginTimeMillis,
+ void getHistoricalOps(int uid, String packageName, in List<String> ops, long beginTimeMillis,
long endTimeMillis, in RemoteCallback callback);
- void getHistoricalOpsFromDiskRaw(int uid, String packageName, in String[] ops,
+ void getHistoricalOpsFromDiskRaw(int uid, String packageName, in List<String> ops,
long beginTimeMillis, long endTimeMillis, in RemoteCallback callback);
void offsetHistory(long duration);
void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index a8ad810..c46f867 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -137,6 +137,7 @@
mDismissStartTarget = mTargets.get(0);
mDismissEndTarget = mTargets.get(mTargets.size() - 1);
mMiddleTarget = mTargets.get(mTargets.size() / 2);
+ mMiddleTarget.isMiddleTarget = true;
}
/**
@@ -438,6 +439,8 @@
public final int flag;
+ public boolean isMiddleTarget;
+
/**
* Multiplier used to calculate distance to snap position. The lower this value, the harder
* it's to snap on this target
diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml
index 1b691d6..c23ca83 100644
--- a/core/res/res/layout/notification_material_media_seekbar.xml
+++ b/core/res/res/layout/notification_material_media_seekbar.xml
@@ -30,6 +30,7 @@
android:maxHeight="3dp"
android:paddingTop="24dp"
android:paddingBottom="24dp"
+ android:clickable="true"
android:layout_marginBottom="-24dp"
android:layout_marginTop="-12dp"
android:splitTrack="false"
diff --git a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
index 02a9adf..bff6b5f 100644
--- a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
@@ -60,7 +60,8 @@
DocumentsContract.buildDocumentUri(TestDocumentsProvider.AUTHORITY, DOCUMENT_ID);
try (ContentProviderClient client =
mResolver.acquireUnstableContentProviderClient(docUri)) {
- final Path actual = DocumentsContract.findDocumentPath(client, docUri);
+ final Path actual = DocumentsContract.findDocumentPath(
+ ContentResolver.wrap(client), docUri);
assertEquals(expected, actual);
}
}
diff --git a/media/OWNERS b/media/OWNERS
index 03b751c..eb26367 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -11,3 +11,6 @@
marcone@google.com
sungsoo@google.com
wjia@google.com
+
+# For maintaining sync with AndroidX code
+per-file ExifInterface.java = jinpark@google.com, sungsoo@google.com
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index e0d178f..29ae1b2 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -137,6 +137,7 @@
static_libs: [
"SystemUI-core",
],
+ resource_dirs: [],
platform_apis: true,
product_specific: true,
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7a7d1f6..bb34a87 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -461,6 +461,9 @@
if (mSnapAlgorithm == null) {
mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets, mDockSide);
+ if (mSnapTargetBeforeMinimized != null && mSnapTargetBeforeMinimized.isMiddleTarget) {
+ mSnapTargetBeforeMinimized = mSnapAlgorithm.getMiddleTarget();
+ }
}
if (mMinimizedSnapAlgorithm == null) {
mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 8160e04..6714b0a 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -660,7 +660,7 @@
++mCount;
} catch (Exception e) {
Slog.e(TAG, "Error when attempting restore: " + e.toString());
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(false);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
}
@@ -686,6 +686,7 @@
boolean staging = !packageName.equals("android");
ParcelFileDescriptor stage;
File downloadFile = (staging) ? mStageName : mBackupDataName;
+ boolean startedAgentRestore = false;
try {
IBackupTransport transport =
@@ -766,13 +767,15 @@
long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
backupManagerService.prepareOperationTimeout(
mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT);
+ startedAgentRestore = true;
mAgent.doRestore(mBackupData, appVersionCode, mNewState,
mEphemeralOpToken, backupManagerService.getBackupManagerBinder());
} catch (Exception e) {
Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
packageName, e.toString());
- keyValueAgentErrorCleanup(); // clears any pending timeout messages as well
+ // Clears any pending timeout messages as well.
+ keyValueAgentErrorCleanup(startedAgentRestore);
// After a restore failure we go back to running the queue. If there
// are no more packages to be restored that will be handled by the
@@ -832,7 +835,7 @@
Slog.e(TAG, "Unable to finalize restore of " + packageName);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
packageName, e.toString());
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(true);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
}
@@ -1110,11 +1113,18 @@
mListener.onFinished(callerLogString);
}
- void keyValueAgentErrorCleanup() {
- // If the agent fails restore, it might have put the app's data
- // into an incoherent state. For consistency we wipe its data
- // again in this case before continuing with normal teardown
- backupManagerService.clearApplicationDataAfterRestoreFailure(mCurrentPackage.packageName);
+ /**
+ * @param clearAppData - set to {@code true} if the backup agent had already been invoked when
+ * restore faied. So the app data may be in corrupted state and has to be cleared.
+ */
+ void keyValueAgentErrorCleanup(boolean clearAppData) {
+ if (clearAppData) {
+ // If the agent fails restore, it might have put the app's data
+ // into an incoherent state. For consistency we wipe its data
+ // again in this case before continuing with normal teardown
+ backupManagerService.clearApplicationDataAfterRestoreFailure(
+ mCurrentPackage.packageName);
+ }
keyValueAgentCleanup();
}
@@ -1251,7 +1261,7 @@
// Some kind of horrible semantic error; we're in an unexpected state.
// Back off hard and wind up.
Slog.e(TAG, "Unexpected restore callback into state " + mState);
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(true);
nextState = UnifiedRestoreState.FINAL;
break;
}
@@ -1271,7 +1281,7 @@
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
mCurrentPackage.packageName, "restore timeout");
// Handle like an agent that threw on invocation: wipe it and go on to the next
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(true);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2f20572..3c0430f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2704,8 +2704,8 @@
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false,
- -1, SYSTEM_UID, UserHandle.USER_ALL);
+ OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -3823,12 +3823,13 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
if (isInstantApp) {
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
- null, null, permission.ACCESS_INSTANT_APPS, null, false, false,
- resolvedUserId, false);
+ broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
+ null, 0, null, null, permission.ACCESS_INSTANT_APPS, null, false,
+ false, resolvedUserId, false);
} else {
- broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
- null, null, null, null, false, false, resolvedUserId, false);
+ broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
+ null, 0, null, null, null, null, false, false, resolvedUserId,
+ false);
}
if (observer != null) {
@@ -4263,7 +4264,8 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid));
+ null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.getUserId(uid));
}
private void cleanupDisabledPackageComponentsLocked(
@@ -8709,6 +8711,8 @@
mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
long ident = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
@@ -8717,7 +8721,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID,
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -8731,7 +8735,8 @@
}
}, 0, null, null,
new String[] {INTERACT_ACROSS_USERS}, OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ UserHandle.USER_ALL);
} catch (Throwable t) {
Slog.wtf(TAG, "Failed sending first user broadcasts", t);
} finally {
@@ -14369,10 +14374,12 @@
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
- sticky, callingPid, callingUid, userId, false /* allowBackgroundActivityStarts */);
+ sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
+ false /* allowBackgroundActivityStarts */);
}
@GuardedBy("this")
@@ -14380,8 +14387,8 @@
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int userId,
- boolean allowBackgroundActivityStarts) {
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId, boolean allowBackgroundActivityStarts) {
intent = new Intent(intent);
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14430,7 +14437,7 @@
// PendingIntent), because that who is actually supplied the arguments.
if (checkComponentPermission(
android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
- Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
+ realCallingPid, realCallingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
@@ -15118,15 +15125,15 @@
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
- callingPid, callingUid, userId);
+ callingPid, callingUid, callingUid, callingPid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
- int broadcastIntentInPackage(String packageName, int uid,
- Intent intent, String resolvedType, IIntentReceiver resultTo,
+ int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+ int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
int userId, boolean allowBackgroundActivityStarts) {
@@ -15139,7 +15146,8 @@
int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras,
requiredPermissions, OP_NONE, bOptions, serialized,
- sticky, -1, uid, userId, allowBackgroundActivityStarts);
+ sticky, -1, uid, realCallingUid, realCallingPid, userId,
+ allowBackgroundActivityStarts);
Binder.restoreCallingIdentity(origId);
return res;
}
@@ -17721,15 +17729,16 @@
}
@Override
- public int broadcastIntentInPackage(String packageName, int uid, Intent intent,
- String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
- boolean sticky, int userId, boolean allowBackgroundActivityStarts) {
+ public int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+ int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
+ int resultCode, String resultData, Bundle resultExtras, String requiredPermission,
+ Bundle bOptions, boolean serialized, boolean sticky, int userId,
+ boolean allowBackgroundActivityStarts) {
synchronized (ActivityManagerService.this) {
return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
- intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermission, bOptions, serialized, sticky, userId,
- allowBackgroundActivityStarts);
+ realCallingUid, realCallingPid, intent, resolvedType, resultTo, resultCode,
+ resultData, resultExtras, requiredPermission, bOptions, serialized, sticky,
+ userId, allowBackgroundActivityStarts);
}
}
@@ -17830,8 +17839,8 @@
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
@@ -17841,8 +17850,8 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
// Send a broadcast to PackageInstallers if the configuration change is interesting
@@ -17857,7 +17866,7 @@
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
permissions, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
}
@@ -17881,7 +17890,8 @@
}
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, -1, SYSTEM_UID, UserHandle.USER_ALL);
+ OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index af56352..a08c829 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -423,9 +423,9 @@
// If a completion callback has been requested, require
// that the broadcast be delivered synchronously
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
- uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
- requiredPermission, options, (finishedReceiver != null),
- false, userId,
+ uid, callingUid, callingPid, finalIntent, resolvedType,
+ finishedReceiver, code, null, null, requiredPermission, options,
+ (finishedReceiver != null), false, userId,
mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
|| allowTrampoline);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 3ea1147..376999d 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -27,6 +27,7 @@
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -108,7 +109,7 @@
mIntent.setComponent(componentName);
mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
- Process.SYSTEM_UID, mUserId);
+ Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
@Override
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 7f6648a..ac20f6c 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -371,7 +371,8 @@
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
- AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
+ AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), userId);
}
// We need to delay unlocking managed profiles until the parent user
@@ -471,7 +472,7 @@
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- userId);
+ Binder.getCallingUid(), Binder.getCallingPid(), userId);
if (getUserInfo(userId).isManagedProfile()) {
UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
@@ -484,8 +485,8 @@
| Intent.FLAG_RECEIVER_FOREGROUND);
mInjector.broadcastIntent(profileUnlockedIntent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID,
- parent.id);
+ null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), parent.id);
}
}
@@ -543,7 +544,8 @@
mInjector.getUserManager().makeInitialized(userInfo.id);
}
}, 0, null, null, null, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
+ null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), userId);
}
}
@@ -573,7 +575,8 @@
}
}, 0, null, null,
new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
- AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
+ AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), userId);
}
int restartUser(final int userId, final boolean foreground) {
@@ -696,7 +699,8 @@
mInjector.broadcastIntent(stoppingIntent,
null, stoppingReceiver, 0, null, null,
new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
});
}
}
@@ -735,7 +739,8 @@
mInjector.broadcastIntent(shutdownIntent,
null, shutdownReceiver, 0, null, null, null,
AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
+ null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), userId);
}
void finishUserStopped(UserState uss) {
@@ -834,7 +839,8 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
/**
@@ -950,6 +956,8 @@
Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground);
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
final int oldUserId = getCurrentUserId();
@@ -1088,7 +1096,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, userId);
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
}
if (foreground) {
@@ -1111,7 +1119,8 @@
}
}, 0, null, null,
new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1427,6 +1436,8 @@
}
void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
long ident = Binder.clearCallingIdentity();
try {
Intent intent;
@@ -1442,7 +1453,8 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ profileUserId);
}
}
if (newUserId >= 0) {
@@ -1457,7 +1469,8 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ profileUserId);
}
intent = new Intent(Intent.ACTION_USER_SWITCHED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -1466,8 +1479,8 @@
mInjector.broadcastIntent(intent,
null, null, 0, null, null,
new String[] {android.Manifest.permission.MANAGE_USERS},
- AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, callingUid,
+ callingPid, UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2107,12 +2120,14 @@
protected int broadcastIntent(Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId) {
// TODO b/64165549 Verify that mLock is not held before calling AMS methods
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
- ordered, sticky, callingPid, callingUid, userId);
+ ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid,
+ userId);
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0e33090..70c28a8 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -38,6 +38,7 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManager.HistoricalOpsRequest;
import android.app.AppOpsManagerInternal;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.content.BroadcastReceiver;
@@ -1024,25 +1025,29 @@
@Override
public void getHistoricalOps(int uid, @NonNull String packageName,
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
@NonNull RemoteCallback callback) {
- Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
- "uid must be " + Process.INVALID_UID + " or non negative");
- Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
- "beginTimeMillis must be non negative and lesser than endTimeMillis");
+ // Use the builder to validate arguments.
+ final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+ beginTimeMillis, endTimeMillis)
+ .setUid(uid)
+ .setPackageName(packageName)
+ .setOpNames(opNames)
+ .build();
Preconditions.checkNotNull(callback, "callback cannot be null");
- checkValidOpsOrNull(opNames);
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+ final String[] opNamesArray = (opNames != null)
+ ? opNames.toArray(new String[opNames.size()]) : null;
if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
// TODO (bug:122218838): Remove once the feature fully enabled.
- getHistoricalPackagesOpsCompat(uid, packageName, opNames, beginTimeMillis,
+ getHistoricalPackagesOpsCompat(uid, packageName, opNamesArray, beginTimeMillis,
endTimeMillis, callback);
} else {
// Must not hold the appops lock
- mHistoricalRegistry.getHistoricalOps(uid, packageName, opNames,
+ mHistoricalRegistry.getHistoricalOps(uid, packageName, opNamesArray,
beginTimeMillis, endTimeMillis, callback);
}
}
@@ -1101,20 +1106,25 @@
@Override
public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
@NonNull RemoteCallback callback) {
- Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
- "uid must be " + Process.INVALID_UID + " or non negative");
- Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
- "beginTimeMillis must be non negative and lesser than endTimeMillis");
+ // Use the builder to validate arguments.
+ final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+ beginTimeMillis, endTimeMillis)
+ .setUid(uid)
+ .setPackageName(packageName)
+ .setOpNames(opNames)
+ .build();
Preconditions.checkNotNull(callback, "callback cannot be null");
- checkValidOpsOrNull(opNames);
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+ final String[] opNamesArray = (opNames != null)
+ ? opNames.toArray(new String[opNames.size()]) : null;
+
// Must not hold the appops lock
- mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNames,
+ mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNamesArray,
beginTimeMillis, endTimeMillis, callback);
}
@@ -4266,16 +4276,6 @@
return packageNames;
}
- private static void checkValidOpsOrNull(String[] opNames) {
- if (opNames != null) {
- for (String opName : opNames) {
- if (AppOpsManager.strOpToOp(opName) == AppOpsManager.OP_NONE) {
- throw new IllegalArgumentException("Unknown op: " + opName);
- }
- }
- }
- }
-
private final class ClientRestrictionState implements DeathRecipient {
private final IBinder token;
SparseArray<boolean[]> perUserRestrictions;
diff --git a/services/core/java/com/android/server/input/InputForwarder.java b/services/core/java/com/android/server/input/InputForwarder.java
deleted file mode 100644
index 00af839..0000000
--- a/services/core/java/com/android/server/input/InputForwarder.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 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.android.server.input;
-
-import android.app.IInputForwarder;
-import android.hardware.input.InputManagerInternal;
-import android.view.InputEvent;
-
-import com.android.server.LocalServices;
-
-import static android.hardware.input.InputManager.INJECT_INPUT_EVENT_MODE_ASYNC;
-
-/**
- * Basic implementation of {@link IInputForwarder}.
- */
-class InputForwarder extends IInputForwarder.Stub {
-
- private final InputManagerInternal mInputManagerInternal;
- private final int mDisplayId;
-
- InputForwarder(int displayId) {
- mDisplayId = displayId;
- mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- }
-
- @Override
- public boolean forwardEvent(InputEvent event) {
- event.setDisplayId(mDisplayId);
- return mInputManagerInternal.injectInputEvent(event, INJECT_INPUT_EVENT_MODE_ASYNC);
- }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 28393a2..87c7441 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.input;
import android.annotation.NonNull;
-import android.app.IInputForwarder;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -1685,29 +1684,6 @@
nativeMonitor(mPtr);
}
- // Binder call
- @Override
- public IInputForwarder createInputForwarder(int displayId) throws RemoteException {
- if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS,
- "createInputForwarder()")) {
- throw new SecurityException("Requires INJECT_EVENTS permission");
- }
- final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- final Display display = displayManager.getDisplay(displayId);
- if (display == null) {
- throw new IllegalArgumentException(
- "Can't create input forwarder for non-existent displayId: " + displayId);
- }
- final int callingUid = Binder.getCallingUid();
- final int displayOwnerUid = display.getOwnerUid();
- if (callingUid != displayOwnerUid) {
- throw new SecurityException(
- "Only owner of the display can forward input events to it.");
- }
-
- return new InputForwarder(displayId);
- }
-
// Native callback.
private void notifyConfigurationChanged(long whenNanos) {
mWindowManagerCallbacks.notifyConfigurationChanged();
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index dac4b6f..e12d1dc 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -167,6 +167,27 @@
}
/**
+ * Marks a staged session as successful.
+ *
+ * <p>Only activated session can be marked as successful.
+ *
+ * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
+ * successful.
+ */
+ void markStagedSessionSuccessful(int sessionId) {
+ try {
+ mApexService.markStagedSessionSuccessful(sessionId);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ } catch (Exception e) {
+ // It is fine to just log an exception in this case. APEXd will be able to recover in
+ // case markStagedSessionSuccessful fails.
+ Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
+ }
+ }
+
+ /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -196,7 +217,7 @@
ipw.increaseIndent();
final ApexSessionInfo[] sessions = mApexService.getSessions();
for (ApexSessionInfo si : sessions) {
- ipw.println("Session ID: " + Integer.toString(si.sessionId));
+ ipw.println("Session ID: " + si.sessionId);
ipw.increaseIndent();
if (si.isUnknown) {
ipw.println("State: UNKNOWN");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 6c212d6..d1ebc94 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -247,7 +247,8 @@
}
private void resumeSession(@NonNull PackageInstallerSession session) {
- if (sessionContainsApex(session)) {
+ boolean hasApex = sessionContainsApex(session);
+ if (hasApex) {
// Check with apexservice whether the apex packages have been activated.
ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
if (apexSessionInfo == null) {
@@ -271,7 +272,7 @@
mBgHandler.post(() -> preRebootVerification(session));
return;
}
- if (!apexSessionInfo.isActivated) {
+ if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
// In all the remaining cases apexd will try to apply the session again at next
// boot. Nothing to do here for now.
Slog.w(TAG, "Staged session " + session.sessionId + " scheduled to be applied "
@@ -287,7 +288,11 @@
+ "more information.");
return;
}
+
session.setStagedSessionApplied();
+ if (hasApex) {
+ mApexManager.markStagedSessionSuccessful(session.sessionId);
+ }
}
private String findFirstAPKInDir(File stageDir) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index ceaf829..05d3c17 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -842,6 +843,7 @@
String packageName = newPackage.packageName;
for (PackageRollbackInfo info : rd.packages) {
if (info.getPackageName().equals(packageName)) {
+ info.getInstalledUsers().addAll(IntArray.wrap(installedUsers));
AppDataRollbackHelper.SnapshotAppDataResult rs =
mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
info.getPendingBackups().addAll(rs.pendingBackups);
@@ -874,7 +876,7 @@
* the child sessions, not the parent session.
*/
private boolean enableRollbackForSession(PackageInstaller.SessionInfo session,
- int[] installedUsers, boolean snapshotUserData) {
+ @NonNull int[] installedUsers, boolean snapshotUserData) {
// TODO: Don't attempt to enable rollback for split installs.
final int installFlags = session.installFlags;
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
@@ -1016,7 +1018,7 @@
}
if (!session.isMultiPackage()) {
- if (!enableRollbackForSession(session, null, false)) {
+ if (!enableRollbackForSession(session, new int[0], false)) {
Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
@@ -1030,7 +1032,7 @@
result.offer(false);
return;
}
- if (!enableRollbackForSession(childSession, null, false)) {
+ if (!enableRollbackForSession(childSession, new int[0], false)) {
Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f33c518..087de69 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -87,8 +87,6 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
@@ -2828,28 +2826,6 @@
outAppBounds.setEmpty();
}
- // TODO(b/112288258): Remove below calculation because the position information in bounds
- // will be replaced by the offset of surface.
- final Rect appBounds = parentConfig.windowConfiguration.getAppBounds();
- if (appBounds != null) {
- final Rect outBounds = inOutConfig.windowConfiguration.getBounds();
- final int activityWidth = outBounds.width();
- final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId());
- if (navBarPosition == NAV_BAR_LEFT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = appBounds.right - activityWidth;
- outBounds.right = appBounds.right;
- } else if (navBarPosition == NAV_BAR_RIGHT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = 0;
- outBounds.right = activityWidth + appBounds.left;
- } else if (appBounds.width() > activityWidth) {
- // Horizontally center the frame.
- outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2;
- outBounds.right = outBounds.left + activityWidth;
- }
- }
-
task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 0a3c2fb..c685b05 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2332,6 +2332,20 @@
if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
throw new IllegalStateException("Task resolved to incompatible display");
}
+
+ final ActivityDisplay preferredDisplay =
+ mRootActivityContainer.getActivityDisplay(preferredDisplayId);
+
+ final boolean singleTaskInstance = preferredDisplay != null
+ && preferredDisplay.isSingleTaskInstance();
+
+ if (singleTaskInstance) {
+ // Suppress the warning toast if the preferredDisplay was set to singleTask.
+ // The singleTaskInstance displays will only contain one task and any attempt to
+ // launch new task will re-route to the default display.
+ return;
+ }
+
if (preferredDisplayId != actualDisplayId) {
Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
// Display a warning toast that we failed to put a task on a secondary display.
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 97062a6..5c528c7 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -568,7 +568,7 @@
final long token = proto.start(fieldId);
mRequestedOverrideConfiguration.writeToProto(proto, OVERRIDE_CONFIGURATION,
- logLevel != WindowTraceLogLevel.CRITICAL);
+ logLevel == WindowTraceLogLevel.CRITICAL);
if (logLevel == WindowTraceLogLevel.ALL) {
mFullConfiguration.writeToProto(proto, FULL_CONFIGURATION, false /* critical */);
mMergedOverrideConfiguration.writeToProto(proto, MERGED_OVERRIDE_CONFIGURATION,
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ea65dd9..1d76a71 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -396,6 +396,10 @@
if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
|| mAdjustedForDivider != adjustedForDivider) {
if (animate && !mAnimatingForMinimizedDockedStack) {
+ // Notify SystemUI to set the target docked stack size according current docked
+ // state without animation when calling startImeAdjustAnimation.
+ notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
+ isHomeStackResizable());
startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
} else {
// Animation might be delayed, so only notify if we don't run an animation.
@@ -889,7 +893,10 @@
}
if (mAnimatingForMinimizedDockedStack) {
return animateForMinimizedDockedStack(now);
- } else if (mAnimatingForIme) {
+ } else if (mAnimatingForIme && !mDisplayContent.mAppTransition.isRunning()) {
+ // To prevent task stack resize animation may flicking when playing app transition
+ // animation & IME window enter animation in parallel, make sure app transition is done
+ // and then start to animate for IME.
return animateForIme(now);
}
return false;
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 59d7560..9d3112f 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -2134,7 +2134,7 @@
if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
inOutConfig.screenHeightDp = insideParentBounds
- ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp)
+ ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
: overrideScreenHeightDp;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7b742fd..b915199 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1163,6 +1163,14 @@
}
private boolean adjustForIME(final WindowState imeWin) {
+ // To prevent task stack resize animation may flicking when playing app transition
+ // animation & IME window enter animation in parallel, we need to make sure app
+ // transition is done and then adjust task size for IME, skip the new adjusted frame when
+ // app transition is still running.
+ if (getDisplayContent().mAppTransition.isRunning()) {
+ return false;
+ }
+
final int dockedSide = getDockSide();
final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
if (imeWin == null || !dockedTopOrBottom) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3430987..21a557e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2164,9 +2164,6 @@
// A modal window uses the whole compatibility bounds.
flags |= FLAG_NOT_TOUCH_MODAL;
mTmpRect.set(mAppToken.getResolvedOverrideBounds());
- // TODO(b/112288258): Remove the forced offset when the override bounds always
- // starts from zero (See {@link ActivityRecord#resolveOverrideConfiguration}).
- mTmpRect.offsetTo(0, 0);
} else {
// Non-modal uses the application based frame.
mTmpRect.set(mWindowFrames.mCompatFrame);
diff --git a/services/devicepolicy/TEST_MAPPING b/services/devicepolicy/TEST_MAPPING
new file mode 100644
index 0000000..ab85a68
--- /dev/null
+++ b/services/devicepolicy/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "CtsDevicePolicyManagerTestCases"
+ }
+ ]
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index bd03a8d..04abeca1 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -403,7 +403,8 @@
protected int broadcastIntent(Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
- boolean sticky, int callingPid, int callingUid, int userId) {
+ boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId) {
Log.i(TAG, "broadcastIntentLocked " + intent);
mSentIntents.add(intent);
return 0;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8c36905..a1db3e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -27,9 +27,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
@@ -158,35 +155,6 @@
assertTrue(mActivity.isState(STOPPED));
}
- @Test
- public void testPositionLimitedAspectRatioNavBarBottom() {
- verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f,
- new Rect(0, 0, 1000, 1500));
- }
-
- @Test
- public void testPositionLimitedAspectRatioNavBarLeft() {
- verifyPositionWithLimitedAspectRatio(NAV_BAR_LEFT, new Rect(0, 0, 2000, 1000), 1.5f,
- new Rect(500, 0, 2000, 1000));
- }
-
- @Test
- public void testPositionLimitedAspectRatioNavBarRight() {
- verifyPositionWithLimitedAspectRatio(NAV_BAR_RIGHT, new Rect(0, 0, 2000, 1000), 1.5f,
- new Rect(0, 0, 1500, 1000));
- }
-
- private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds,
- float aspectRatio, Rect expectedActivityBounds) {
- // Verify with nav bar on the right.
- when(mService.mWindowManager.getNavBarPosition(mActivity.getDisplayId()))
- .thenReturn(navBarPosition);
- mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
- mActivity.info.maxAspectRatio = aspectRatio;
- ensureActivityConfiguration();
- assertEquals(expectedActivityBounds, mActivity.getBounds());
- }
-
private void ensureActivityConfiguration() {
mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index bcf9dd2..388f98f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -24,6 +24,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -307,6 +308,41 @@
assertEquals(fullScreenBounds, task.getBounds());
}
+ @Test
+ public void testComputeConfigResourceOverrides() {
+ final TaskRecord task = new TaskBuilder(mSupervisor).build();
+ final Configuration inOutConfig = new Configuration();
+ final Configuration parentConfig = new Configuration();
+ final int longSide = 1200;
+ final int shortSide = 600;
+ parentConfig.densityDpi = 400;
+ parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
+ parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
+
+ // Portrait bounds.
+ inOutConfig.windowConfiguration.getBounds().set(0, 0, shortSide, longSide);
+ // By default, the parent bounds should limit the existing input bounds.
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
+ assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, inOutConfig.orientation);
+
+ inOutConfig.setToDefaults();
+ // Landscape bounds.
+ inOutConfig.windowConfiguration.getBounds().set(0, 0, longSide, shortSide);
+ // Without limiting to be inside the parent bounds, the out screen size should keep relative
+ // to the input bounds.
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig,
+ false /* insideParentBounds */);
+
+ assertEquals(shortSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+ inOutConfig.screenHeightDp);
+ assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+ inOutConfig.screenWidthDp);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
+ }
+
/** Ensures that the alias intent won't have target component resolved. */
@Test
public void testTaskIntentActivityAlias() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 3eb9085..b0e20b8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -35,6 +35,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -54,7 +55,6 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -87,6 +87,7 @@
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 124127512)
public class WindowStateTests extends WindowTestsBase {
private static int sPreviousNewInsetsMode;
@@ -389,6 +390,7 @@
}
@Test
+ @FlakyTest(bugId = 74078662)
public void testLayoutSeqResetOnReparent() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
app.mLayoutSeq = 1;
@@ -445,6 +447,7 @@
}
@Test
+ @FlakyTest(bugId = 74078662)
public void testDisplayCutoutIsCalculatedRelativeToFrame() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
WindowFrames wf = app.getWindowFrames();
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index 40d4eff..0967ad3 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -71,7 +71,7 @@
# RollbackTest
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, RollbackTest/src)
LOCAL_PACKAGE_NAME := RollbackTest
LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
@@ -84,10 +84,21 @@
$(ROLLBACK_TEST_APP_BV1) \
$(ROLLBACK_TEST_APP_BV2) \
$(ROLLBACK_TEST_APEX_V2)
+LOCAL_MANIFEST_FILE := RollbackTest/AndroidManifest.xml
LOCAL_SDK_VERSION := system_current
LOCAL_TEST_CONFIG := RollbackTest.xml
include $(BUILD_PACKAGE)
+# StagedRollbackTest
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, StagedRollbackTest/src)
+LOCAL_MODULE := StagedRollbackTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_JAVA_LIBRARIES := tradefed
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_TEST_CONFIG := StagedRollbackTest.xml
+include $(BUILD_HOST_JAVA_LIBRARY)
+
# Clean up local variables
ROLLBACK_TEST_APP_AV1 :=
ROLLBACK_TEST_APP_AV2 :=
diff --git a/tests/RollbackTest/README.txt b/tests/RollbackTest/README.txt
new file mode 100644
index 0000000..c0b718a
--- /dev/null
+++ b/tests/RollbackTest/README.txt
@@ -0,0 +1,23 @@
+This directory contains a test for the rollback manager service.
+
+Directory structure
+===================
+RollbackTest
+ - device driven test for rollbacks not involving staged rollbacks.
+
+StagedRollbackTest
+ - device driven test for staged rollbacks.
+
+TestApp
+ - source for dummy apks used in testing.
+
+TestApex
+ - source for dummy apex modules used in testing.
+
+Running the tests
+=================
+
+You can manually run the tests as follows:
+
+ atest RollbackTest
+ atest StagedRollbackTest
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index adbad56..ac39f85 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -21,5 +21,9 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.tests.rollback" />
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+
+ <!-- Exclude the StagedRollbackTest tests, which needs to be specially
+ driven from the StagedRollbackTest host test -->
+ <option name="exclude-filter" value="com.android.tests.rollback.StagedRollbackTest" />
</test>
</configuration>
diff --git a/tests/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
similarity index 100%
rename from tests/RollbackTest/AndroidManifest.xml
rename to tests/RollbackTest/RollbackTest/AndroidManifest.xml
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
similarity index 100%
rename from tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
rename to tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
similarity index 100%
rename from tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
rename to tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
similarity index 92%
rename from tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
rename to tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index f07ae9f..f3edf09 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -16,6 +16,10 @@
package com.android.tests.rollback;
+import static com.android.tests.rollback.RollbackTestUtils.assertPackageRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
+
import android.Manifest;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
@@ -24,7 +28,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.VersionedPackage;
-import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Handler;
@@ -42,7 +45,6 @@
import org.junit.runners.JUnit4;
import java.util.Collections;
-import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
@@ -617,17 +619,6 @@
}
}
- // Helper function to test the value of a PackageRollbackInfo
- private void assertPackageRollbackInfoEquals(String packageName,
- long versionRolledBackFrom, long versionRolledBackTo,
- PackageRollbackInfo info) {
- assertEquals(packageName, info.getPackageName());
- assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
- assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
- assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
- assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
- }
-
/**
* Test bad update automatic rollback.
*/
@@ -713,23 +704,6 @@
}
}
- // Helper function to test the value of a RollbackInfo with single package
- private void assertRollbackInfoEquals(String packageName,
- long versionRolledBackFrom, long versionRolledBackTo,
- RollbackInfo info, VersionedPackage... causePackages) {
- assertNotNull(info);
- assertEquals(1, info.getPackages().size());
- assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
- info.getPackages().get(0));
- assertEquals(causePackages.length, info.getCausePackages().size());
- for (int i = 0; i < causePackages.length; ++i) {
- assertEquals(causePackages[i].getPackageName(),
- info.getCausePackages().get(i).getPackageName());
- assertEquals(causePackages[i].getLongVersionCode(),
- info.getCausePackages().get(i).getLongVersionCode());
- }
- }
-
// Helper function to test that the given rollback info is a rollback for
// the atomic set {A2, B2} -> {A1, B1}.
private void assertRollbackInfoForAandB(RollbackInfo rollback) {
@@ -743,23 +717,4 @@
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(1));
}
}
-
- // Helper function to return the RollbackInfo with a given package in the
- // list of rollbacks. Throws an assertion failure if there is more than
- // one such rollback info. Returns null if there are no such rollback
- // infos.
- private RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
- String packageName) {
- RollbackInfo found = null;
- for (RollbackInfo rollback : rollbacks) {
- for (PackageRollbackInfo info : rollback.getPackages()) {
- if (packageName.equals(info.getPackageName())) {
- assertNull(found);
- found = rollback;
- break;
- }
- }
- }
- return found;
- }
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
new file mode 100644
index 0000000..280ee1d
--- /dev/null
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2018 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.android.tests.rollback;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Utilities to facilitate testing rollbacks.
+ */
+class RollbackTestUtils {
+
+ private static final String TAG = "RollbackTest";
+
+ static RollbackManager getRollbackManager() {
+ Context context = InstrumentationRegistry.getContext();
+ RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
+ if (rm == null) {
+ throw new AssertionError("Failed to get RollbackManager");
+ }
+ return rm;
+ }
+
+ /**
+ * Returns the version of the given package installed on device.
+ * Returns -1 if the package is not currently installed.
+ */
+ static long getInstalledVersion(String packageName) {
+ Context context = InstrumentationRegistry.getContext();
+ PackageManager pm = context.getPackageManager();
+ try {
+ PackageInfo info = pm.getPackageInfo(packageName, 0);
+ return info.getLongVersionCode();
+ } catch (PackageManager.NameNotFoundException e) {
+ return -1;
+ }
+ }
+
+ private static void assertStatusSuccess(Intent result) {
+ int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == -1) {
+ throw new AssertionError("PENDING USER ACTION");
+ } else if (status > 0) {
+ String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
+ }
+ }
+
+ /**
+ * Uninstalls the given package.
+ * Does nothing if the package is not installed.
+ * @throws AssertionError if package can't be uninstalled.
+ */
+ static void uninstall(String packageName) throws InterruptedException, IOException {
+ // No need to uninstall if the package isn't installed.
+ if (getInstalledVersion(packageName) == -1) {
+ return;
+ }
+
+ Context context = InstrumentationRegistry.getContext();
+ PackageManager packageManager = context.getPackageManager();
+ PackageInstaller packageInstaller = packageManager.getPackageInstaller();
+ packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
+ assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ }
+
+ /**
+ * Commit the given rollback.
+ * @throws AssertionError if the rollback fails.
+ */
+ static void rollback(int rollbackId, VersionedPackage... causePackages)
+ throws InterruptedException {
+ RollbackManager rm = getRollbackManager();
+ rm.commitRollback(rollbackId, Arrays.asList(causePackages),
+ LocalIntentSender.getIntentSender());
+ Intent result = LocalIntentSender.getIntentSenderResult();
+ int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+ RollbackManager.STATUS_FAILURE);
+ if (status != RollbackManager.STATUS_SUCCESS) {
+ String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
+ throw new AssertionError(message);
+ }
+ }
+
+ /**
+ * Installs the apk with the given name.
+ *
+ * @param resourceName name of class loader resource for the apk to
+ * install.
+ * @param enableRollback if rollback should be enabled.
+ * @throws AssertionError if the installation fails.
+ */
+ static void install(String resourceName, boolean enableRollback)
+ throws InterruptedException, IOException {
+ Context context = InstrumentationRegistry.getContext();
+ PackageInstaller.Session session = null;
+ PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ if (enableRollback) {
+ params.setEnableRollback();
+ }
+ int sessionId = packageInstaller.createSession(params);
+ session = packageInstaller.openSession(sessionId);
+
+ ClassLoader loader = RollbackTest.class.getClassLoader();
+ try (OutputStream packageInSession = session.openWrite("package", 0, -1);
+ InputStream is = loader.getResourceAsStream(resourceName);) {
+ byte[] buffer = new byte[4096];
+ int n;
+ while ((n = is.read(buffer)) >= 0) {
+ packageInSession.write(buffer, 0, n);
+ }
+ }
+
+ // Commit the session (this will start the installation workflow).
+ session.commit(LocalIntentSender.getIntentSender());
+ assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ }
+
+ /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
+ static void launchPackage(String packageName)
+ throws InterruptedException, IOException {
+ Context context = InstrumentationRegistry.getContext();
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setPackage(packageName);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Installs the apks with the given resource names as an atomic set.
+ * <p>
+ * In case of staged installs, this function will return succesfully after
+ * the staged install has been committed and is ready for the device to
+ * reboot.
+ *
+ * @param staged if the rollback should be staged.
+ * @param enableRollback if rollback should be enabled.
+ * @param resourceNames names of the class loader resource for the apks to
+ * install.
+ * @throws AssertionError if the installation fails.
+ */
+ private static void install(boolean staged, boolean enableRollback,
+ String... resourceNames) throws InterruptedException, IOException {
+ Context context = InstrumentationRegistry.getContext();
+ PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+
+ PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ multiPackageParams.setMultiPackage();
+ if (staged) {
+ multiPackageParams.setStaged();
+ }
+ if (enableRollback) {
+ // TODO: Do we set this on the parent params, the child params, or
+ // both?
+ multiPackageParams.setEnableRollback();
+ }
+ int multiPackageId = packageInstaller.createSession(multiPackageParams);
+ PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
+
+ for (String resourceName : resourceNames) {
+ PackageInstaller.Session session = null;
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ if (staged) {
+ params.setStaged();
+ }
+ if (enableRollback) {
+ params.setEnableRollback();
+ }
+ int sessionId = packageInstaller.createSession(params);
+ session = packageInstaller.openSession(sessionId);
+
+ ClassLoader loader = RollbackTest.class.getClassLoader();
+ try (OutputStream packageInSession = session.openWrite("package", 0, -1);
+ InputStream is = loader.getResourceAsStream(resourceName);) {
+ byte[] buffer = new byte[4096];
+ int n;
+ while ((n = is.read(buffer)) >= 0) {
+ packageInSession.write(buffer, 0, n);
+ }
+ }
+ multiPackage.addChildSessionId(sessionId);
+ }
+
+ // Commit the session (this will start the installation workflow).
+ multiPackage.commit(LocalIntentSender.getIntentSender());
+ assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+
+ if (staged) {
+ waitForSessionReady(multiPackageId);
+ }
+ }
+
+ /**
+ * Installs the apks with the given resource names as an atomic set.
+ *
+ * @param enableRollback if rollback should be enabled.
+ * @param resourceNames names of the class loader resource for the apks to
+ * install.
+ * @throws AssertionError if the installation fails.
+ */
+ static void installMultiPackage(boolean enableRollback, String... resourceNames)
+ throws InterruptedException, IOException {
+ install(false, enableRollback, resourceNames);
+ }
+
+ /**
+ * Installs the apks with the given resource names as a staged atomic set.
+ *
+ * @param enableRollback if rollback should be enabled.
+ * @param resourceNames names of the class loader resource for the apks to
+ * install.
+ * @throws AssertionError if the installation fails.
+ */
+ static void installStaged(boolean enableRollback, String... resourceNames)
+ throws InterruptedException, IOException {
+ install(true, enableRollback, resourceNames);
+ }
+
+ static void adoptShellPermissionIdentity(String... permissions) {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity(permissions);
+ }
+
+ static void dropShellPermissionIdentity() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ /**
+ * Returns the RollbackInfo with a given package in the list of rollbacks.
+ * Throws an assertion failure if there is more than one such rollback
+ * info. Returns null if there are no such rollback infos.
+ */
+ static RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
+ String packageName) {
+ RollbackInfo found = null;
+ for (RollbackInfo rollback : rollbacks) {
+ for (PackageRollbackInfo info : rollback.getPackages()) {
+ if (packageName.equals(info.getPackageName())) {
+ assertNull(found);
+ found = rollback;
+ break;
+ }
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Asserts that the given PackageRollbackInfo has the expected package
+ * name and versions.
+ */
+ static void assertPackageRollbackInfoEquals(String packageName,
+ long versionRolledBackFrom, long versionRolledBackTo,
+ PackageRollbackInfo info) {
+ assertEquals(packageName, info.getPackageName());
+ assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
+ assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
+ assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
+ assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
+ }
+
+ /**
+ * Asserts that the given RollbackInfo has a single package with expected
+ * package name and versions.
+ */
+ static void assertRollbackInfoEquals(String packageName,
+ long versionRolledBackFrom, long versionRolledBackTo,
+ RollbackInfo info, VersionedPackage... causePackages) {
+ assertNotNull(info);
+ assertEquals(1, info.getPackages().size());
+ assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
+ info.getPackages().get(0));
+ assertEquals(causePackages.length, info.getCausePackages().size());
+ for (int i = 0; i < causePackages.length; ++i) {
+ assertEquals(causePackages[i].getPackageName(),
+ info.getCausePackages().get(i).getPackageName());
+ assertEquals(causePackages[i].getLongVersionCode(),
+ info.getCausePackages().get(i).getLongVersionCode());
+ }
+ }
+
+ /**
+ * Waits for the given session to be marked as ready.
+ * Throws an assertion if the session fails.
+ */
+ static void waitForSessionReady(int sessionId) {
+ BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
+ BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ PackageInstaller.SessionInfo info =
+ intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
+ if (info != null && info.getSessionId() == sessionId) {
+ if (info.isSessionReady() || info.isSessionFailed()) {
+ try {
+ sessionStatus.put(info);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Failed to put session info.", e);
+ }
+ }
+ }
+ }
+ };
+ IntentFilter sessionUpdatedFilter =
+ new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
+
+ Context context = InstrumentationRegistry.getContext();
+ context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
+
+ PackageInstaller installer = context.getPackageManager().getPackageInstaller();
+ PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
+
+ try {
+ if (info.isSessionReady() || info.isSessionFailed()) {
+ sessionStatus.put(info);
+ }
+
+ info = sessionStatus.take();
+ context.unregisterReceiver(sessionUpdatedReceiver);
+ if (info.isSessionFailed()) {
+ throw new AssertionError(info.getStagedSessionErrorMessage());
+ }
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
new file mode 100644
index 0000000..297bf86
--- /dev/null
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 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.android.tests.rollback;
+
+import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
+
+import android.Manifest;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for rollback of staged installs.
+ * <p>
+ * Note: These tests require reboot in between test phases. They are run
+ * specially so that the testFooEnableRollback, testFooCommitRollback, and
+ * testFooConfirmRollback phases of each test are run in order with reboots in
+ * between them.
+ */
+@RunWith(JUnit4.class)
+public class StagedRollbackTest {
+
+ private static final String TAG = "RollbackTest";
+ private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
+
+ /**
+ * Adopts common shell permissions needed for rollback tests.
+ */
+ @Before
+ public void adoptShellPermissions() {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+ }
+
+ /**
+ * Drops shell permissions needed for rollback tests.
+ */
+ @After
+ public void dropShellPermissions() {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+
+
+ /**
+ * Test basic rollbacks. Enable rollback phase.
+ */
+ @Test
+ public void testBasicEnableRollback() throws Exception {
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.installStaged(true, "RollbackTestAppAv2.apk");
+
+ // At this point, the host test driver will reboot the device and run
+ // testBasicCommitRollback().
+ }
+
+ /**
+ * Test basic rollbacks. Commit rollback phase.
+ */
+ @Test
+ public void testBasicCommitRollback() throws Exception {
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ assertTrue(rollback.isStaged());
+
+ RollbackTestUtils.rollback(rollback.getRollbackId());
+
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ assertTrue(rollback.isStaged());
+ assertNotEquals(-1, rollback.getCommittedSessionId());
+
+ RollbackTestUtils.waitForSessionReady(rollback.getCommittedSessionId());
+
+ // The app should not be rolled back until after reboot.
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // At this point, the host test driver will reboot the device and run
+ // testBasicConfirmRollback().
+ }
+
+ /**
+ * Test basic rollbacks. Confirm rollback phase.
+ */
+ @Test
+ public void testBasicConfirmRollback() throws Exception {
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ assertTrue(rollback.isStaged());
+ assertNotEquals(-1, rollback.getCommittedSessionId());
+ }
+}
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
new file mode 100644
index 0000000..2750d37
--- /dev/null
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Runs the staged rollback tests">
+ <option name="test-suite-tag" value="StagedRollbackTest" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RollbackTest.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
+ </test>
+</configuration>
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
new file mode 100644
index 0000000..6cb0dd0
--- /dev/null
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 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.android.tests.rollback.host;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Runs the staged rollback tests.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class StagedRollbackTest extends BaseHostJUnit4Test {
+
+ /**
+ * Runs the given phase of a test by calling into the device.
+ * Throws an exception if the test phase fails.
+ * <p>
+ * For example, <code>runPhase("testBasicEnableRollback");</code>
+ */
+ private void runPhase(String phase) throws Exception {
+ assertTrue(runDeviceTests("com.android.tests.rollback",
+ "com.android.tests.rollback.StagedRollbackTest",
+ phase));
+ }
+
+ /**
+ * Tests staged rollbacks.
+ */
+ @Test
+ public void testBasic() throws Exception {
+ runPhase("testBasicEnableRollback");
+ getDevice().reboot();
+ runPhase("testBasicCommitRollback");
+ getDevice().reboot();
+ runPhase("testBasicConfirmRollback");
+ }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
deleted file mode 100644
index 60c7a59..0000000
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2018 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.android.tests.rollback;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.content.rollback.RollbackManager;
-import android.support.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-
-/**
- * Utilities to facilitate testing rollbacks.
- */
-class RollbackTestUtils {
-
- private static final String TAG = "RollbackTest";
-
- static RollbackManager getRollbackManager() {
- Context context = InstrumentationRegistry.getContext();
- RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
- if (rm == null) {
- throw new AssertionError("Failed to get RollbackManager");
- }
- return rm;
- }
-
- /**
- * Returns the version of the given package installed on device.
- * Returns -1 if the package is not currently installed.
- */
- static long getInstalledVersion(String packageName) {
- Context context = InstrumentationRegistry.getContext();
- PackageManager pm = context.getPackageManager();
- try {
- PackageInfo info = pm.getPackageInfo(packageName, 0);
- return info.getLongVersionCode();
- } catch (PackageManager.NameNotFoundException e) {
- return -1;
- }
- }
-
- private static void assertStatusSuccess(Intent result) {
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == -1) {
- throw new AssertionError("PENDING USER ACTION");
- } else if (status > 0) {
- String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
- }
- }
-
- /**
- * Uninstalls the given package.
- * Does nothing if the package is not installed.
- * @throws AssertionError if package can't be uninstalled.
- */
- static void uninstall(String packageName) throws InterruptedException, IOException {
- // No need to uninstall if the package isn't installed.
- if (getInstalledVersion(packageName) == -1) {
- return;
- }
-
- Context context = InstrumentationRegistry.getContext();
- PackageManager packageManager = context.getPackageManager();
- PackageInstaller packageInstaller = packageManager.getPackageInstaller();
- packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
- }
-
- /**
- * Commit the given rollback.
- * @throws AssertionError if the rollback fails.
- */
- static void rollback(int rollbackId, VersionedPackage... causePackages)
- throws InterruptedException {
- RollbackManager rm = getRollbackManager();
- rm.commitRollback(rollbackId, Arrays.asList(causePackages),
- LocalIntentSender.getIntentSender());
- Intent result = LocalIntentSender.getIntentSenderResult();
- int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
- RollbackManager.STATUS_FAILURE);
- if (status != RollbackManager.STATUS_SUCCESS) {
- String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message);
- }
- }
-
- /**
- * Installs the apk with the given name.
- *
- * @param resourceName name of class loader resource for the apk to
- * install.
- * @param enableRollback if rollback should be enabled.
- * @throws AssertionError if the installation fails.
- */
- static void install(String resourceName, boolean enableRollback)
- throws InterruptedException, IOException {
- Context context = InstrumentationRegistry.getContext();
- PackageInstaller.Session session = null;
- PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- if (enableRollback) {
- params.setEnableRollback();
- }
- int sessionId = packageInstaller.createSession(params);
- session = packageInstaller.openSession(sessionId);
-
- ClassLoader loader = RollbackTest.class.getClassLoader();
- try (OutputStream packageInSession = session.openWrite("package", 0, -1);
- InputStream is = loader.getResourceAsStream(resourceName);) {
- byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- packageInSession.write(buffer, 0, n);
- }
- }
-
- // Commit the session (this will start the installation workflow).
- session.commit(LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
- }
-
- /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
- static void launchPackage(String packageName)
- throws InterruptedException, IOException {
- Context context = InstrumentationRegistry.getContext();
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setPackage(packageName);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- context.startActivity(intent);
- }
-
- /**
- * Installs the apks with the given resource names as an atomic set.
- *
- * @param enableRollback if rollback should be enabled.
- * @param resourceNames names of the class loader resource for the apks to
- * install.
- * @throws AssertionError if the installation fails.
- */
- static void installMultiPackage(boolean enableRollback, String... resourceNames)
- throws InterruptedException, IOException {
- Context context = InstrumentationRegistry.getContext();
- PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
-
- PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- multiPackageParams.setMultiPackage();
- if (enableRollback) {
- // TODO: Do we set this on the parent params, the child params, or
- // both?
- multiPackageParams.setEnableRollback();
- }
- int multiPackageId = packageInstaller.createSession(multiPackageParams);
- PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
-
- for (String resourceName : resourceNames) {
- PackageInstaller.Session session = null;
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- if (enableRollback) {
- params.setEnableRollback();
- }
- int sessionId = packageInstaller.createSession(params);
- session = packageInstaller.openSession(sessionId);
-
- ClassLoader loader = RollbackTest.class.getClassLoader();
- try (OutputStream packageInSession = session.openWrite("package", 0, -1);
- InputStream is = loader.getResourceAsStream(resourceName);) {
- byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- packageInSession.write(buffer, 0, n);
- }
- }
- multiPackage.addChildSessionId(sessionId);
- }
-
- // Commit the session (this will start the installation workflow).
- multiPackage.commit(LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
- }
-
- static void adoptShellPermissionIdentity(String... permissions) {
- InstrumentationRegistry
- .getInstrumentation()
- .getUiAutomation()
- .adoptShellPermissionIdentity(permissions);
- }
-
- static void dropShellPermissionIdentity() {
- InstrumentationRegistry
- .getInstrumentation()
- .getUiAutomation()
- .dropShellPermissionIdentity();
- }
-}