diff options
66 files changed, 1453 insertions, 505 deletions
diff --git a/api/current.txt b/api/current.txt index fe86cbe48375..1c60efa62be3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -9348,25 +9348,7 @@ package android.content { 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 @@ package android.content { 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 @@ package android.content { 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 @@ package android.content { 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"; @@ -26008,6 +25992,7 @@ package android.media { method public void broadcastSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle); method public void cancelSessionCommand(@NonNull android.media.MediaSession2.ControllerInfo, @NonNull Object); method public void close(); + method @NonNull public java.util.List<android.media.MediaSession2.ControllerInfo> getConnectedControllers(); method @NonNull public String getSessionId(); method @NonNull public android.media.Session2Token getSessionToken(); method public boolean isPlaybackActive(); @@ -38170,38 +38155,26 @@ package android.provider { 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 142068cdb48f..128ee99c27ad 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -304,7 +304,7 @@ package android.app { } 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 @@ package android.app { 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.bluetooth.le { 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); @@ -5328,6 +5339,7 @@ package android.os { public final class PowerManager { method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend(); method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveMode(); method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean); method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig); diff --git a/api/test-current.txt b/api/test-current.txt index 16098c1a80fa..01678b1c1066 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -101,8 +101,8 @@ package android.app { 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 @@ package android.app { 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.bluetooth { 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/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index d7ab6e5f89bb..2585a5b27681 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -4821,6 +4821,12 @@ message AppCompacted { // The process state at the time of compaction. optional android.app.ProcessStateEnum process_state = 16 [default = PROCESS_STATE_UNKNOWN]; + + // Free ZRAM in kilobytes before compaction. + optional int64 before_zram_free_kilobytes = 17; + + // Free ZRAM in kilobytes after compaction. + optional int64 after_zram_free_kilobytes = 18; } /** diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java index d29e68e5a187..3180b77f5700 100644 --- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -26,6 +26,8 @@ import android.os.SystemClock; import android.os.SystemProperties; public class PowerCommand extends Svc.Command { + private static final int FORCE_SUSPEND_DELAY_DEFAULT_MILLIS = 0; + public PowerCommand() { super("power"); } @@ -42,7 +44,17 @@ public class PowerCommand extends Svc.Command { + " svc power reboot [reason]\n" + " Perform a runtime shutdown and reboot device with specified reason.\n" + " svc power shutdown\n" - + " Perform a runtime shutdown and power off the device.\n"; + + " Perform a runtime shutdown and power off the device.\n" + + " svc power forcesuspend [t]\n" + + " Force the system into suspend, ignoring all wakelocks.\n" + + " t - Number of milliseconds to wait before issuing force-suspend.\n" + + " Helps with devices that can't suspend while plugged in.\n" + + " Defaults to " + FORCE_SUSPEND_DELAY_DEFAULT_MILLIS + ".\n" + + " When using a delay, you must use the nohup shell modifier:\n" + + " 'adb shell nohup svc power forcesuspend [time]'\n" + + " Use caution; this is dangerous. It puts the device to sleep\n" + + " immediately without giving apps or the system an opportunity to\n" + + " save their state.\n"; } public void run(String[] args) { @@ -101,6 +113,20 @@ public class PowerCommand extends Svc.Command { maybeLogRemoteException("Failed to shutdown."); } return; + } else if ("forcesuspend".equals(args[1])) { + int delayMillis = args.length > 2 + ? Integer.parseInt(args[2]) : FORCE_SUSPEND_DELAY_DEFAULT_MILLIS; + try { + Thread.sleep(delayMillis); + if (!pm.forceSuspend()) { + System.err.println("Failed to force suspend."); + } + } catch (InterruptedException e) { + System.err.println("Failed to force suspend: " + e); + } catch (RemoteException e) { + maybeLogRemoteException("Failed to force-suspend with exception: " + e); + } + return; } } } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 69c450cee364..7d828d87e278 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -259,10 +259,11 @@ public abstract class ActivityManagerInternal { 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 ce7199816726..bcbeb220bfb2 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -291,6 +291,9 @@ public class ActivityView extends ViewGroup { /** 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 @@ public class ActivityView extends ViewGroup { /** 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 13eec580ec14..040ad062e512 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -46,6 +46,8 @@ import android.util.ArrayMap; 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 @@ public class AppOpsManager { } /** + * 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 @@ public class AppOpsManager { /** * 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 @@ public class AppOpsManager { @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 @@ public class AppOpsManager { /** * 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 @@ public class AppOpsManager { */ @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/admin/TEST_MAPPING b/core/java/android/app/admin/TEST_MAPPING new file mode 100644 index 000000000000..8f88c2243d50 --- /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 3d732eb7678d..d41d8d9cc1e2 100644 --- a/core/java/android/content/ContentInterface.java +++ b/core/java/android/content/ContentInterface.java @@ -36,6 +36,8 @@ import java.util.ArrayList; * 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 f138d39b7fb0..e06322df7a7f 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -134,7 +134,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall 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 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall 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 7672ccfcd995..bbfa5cceec1d 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -609,10 +609,60 @@ public abstract class ContentResolver implements ContentInterface { 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 abstract class ContentResolver implements ContentInterface { 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 @@ public abstract class ContentResolver implements ContentInterface { 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 @@ public abstract class ContentResolver implements ContentInterface { @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 @@ public abstract class ContentResolver implements ContentInterface { @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 @@ public abstract class ContentResolver implements ContentInterface { @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 abstract class ContentResolver implements ContentInterface { 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 @@ public abstract class ContentResolver implements ContentInterface { @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 @@ public abstract class ContentResolver implements ContentInterface { @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 abstract class ContentResolver implements ContentInterface { 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 abstract class ContentResolver implements ContentInterface { 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 @@ public abstract class ContentResolver implements ContentInterface { 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 @@ public abstract class ContentResolver implements ContentInterface { @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 abstract class ContentResolver implements ContentInterface { 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 @@ public abstract class ContentResolver implements ContentInterface { @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 @@ public abstract class ContentResolver implements ContentInterface { @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 @@ public abstract class ContentResolver implements ContentInterface { @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 f413d7cc92af..0c07a67e917d 100644 --- a/core/java/android/hardware/display/ColorDisplayManager.java +++ b/core/java/android/hardware/display/ColorDisplayManager.java @@ -65,7 +65,8 @@ public final class ColorDisplayManager { @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 44b653c314ad..8a0a9c7c9d9d 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -563,7 +563,8 @@ public final class DisplayManager { * 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/os/Debug.java b/core/java/android/os/Debug.java index aba81af00282..149ef54462dc 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -2439,4 +2439,11 @@ public final class Debug VMDebug.attachAgent(library + "=" + options, classLoader); } } + + /** + * Return the current free ZRAM usage in kilobytes. + * + * @hide + */ + public static native long getZramFreeKb(); } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index bdef57518ac9..483c41a8e48a 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -74,4 +74,7 @@ interface IPowerManager // controls whether PowerManager should doze after the screen turns off or not void setDozeAfterScreenOff(boolean on); + + // Forces the system to suspend even if there are held wakelocks. + boolean forceSuspend(); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index cfe2d28f1024..6bd1f2b59fad 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -363,10 +363,15 @@ public final class PowerManager { public static final int USER_ACTIVITY_FLAG_INDIRECT = 1 << 1; /** + * @hide + */ + public static final int GO_TO_SLEEP_REASON_MIN = 0; + + /** * Go to sleep reason code: Going to sleep due by application request. * @hide */ - public static final int GO_TO_SLEEP_REASON_APPLICATION = 0; + public static final int GO_TO_SLEEP_REASON_APPLICATION = GO_TO_SLEEP_REASON_MIN; /** * Go to sleep reason code: Going to sleep due by request of the @@ -412,6 +417,17 @@ public final class PowerManager { public static final int GO_TO_SLEEP_REASON_ACCESSIBILITY = 7; /** + * Go to sleep reason code: Going to sleep due to force-suspend. + * @hide + */ + public static final int GO_TO_SLEEP_REASON_FORCE_SUSPEND = 8; + + /** + * @hide + */ + public static final int GO_TO_SLEEP_REASON_MAX = GO_TO_SLEEP_REASON_FORCE_SUSPEND; + + /** * @hide */ public static String sleepReasonToString(int sleepReason) { @@ -424,6 +440,7 @@ public final class PowerManager { case GO_TO_SLEEP_REASON_HDMI: return "hdmi"; case GO_TO_SLEEP_REASON_SLEEP_BUTTON: return "sleep_button"; case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility"; + case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend"; default: return Integer.toString(sleepReason); } } @@ -1853,6 +1870,32 @@ public final class PowerManager { } /** + * Forces the device to go to suspend, even if there are currently wakelocks being held. + * <b>Caution</b> + * This is a very dangerous command as it puts the device to sleep immediately. Apps and parts + * of the system will not be notified and will not have an opportunity to save state prior to + * the device going to suspend. + * This method should only be used in very rare circumstances where the device is intended + * to appear as completely off to the user and they have a well understood, reliable way of + * re-enabling it. + * </p><p> + * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * </p> + * + * @return true on success, false otherwise. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public boolean forceSuspend() { + try { + return mService.forceSuspend(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes. * This broadcast is only sent to registered receivers. */ diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 570834265237..d28296786759 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -1281,8 +1281,9 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { } } - @Deprecated - public static boolean deleteDocument(ContentResolver content, Uri documentUri) - throws FileNotFoundException { - return deleteDocument((ContentInterface) content, documentUri); - } - /** * Copies the given document. * @@ -1448,8 +1420,9 @@ public final class DocumentsContract { * 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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * 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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 @@ public final class DocumentsContract { * @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 @@ public final class DocumentsContract { } } - @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 c4ab91f8b429..8a90cade35a2 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -44,9 +44,9 @@ interface IAppOpsService { 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/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index e9035ed102ae..195fe58f0beb 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -737,6 +737,25 @@ static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz, return env->NewStringUTF(s.c_str()); } +static jlong android_os_Debug_getFreeZramKb(JNIEnv* env, jobject clazz) { + + jlong zramFreeKb = 0; + + std::string status_path = android::base::StringPrintf("/proc/meminfo"); + UniqueFile file = MakeUniqueFile(status_path.c_str(), "re"); + + char line[256]; + while (file != nullptr && fgets(line, sizeof(line), file.get())) { + jlong v; + if (sscanf(line, "SwapFree: %" SCNd64 " kB", &v) == 1) { + zramFreeKb = v; + break; + } + } + + return zramFreeKb; +} + /* * JNI registration. */ @@ -778,6 +797,8 @@ static const JNINativeMethod gMethods[] = { (void*)android_os_Debug_dumpNativeBacktraceToFileTimeout }, { "getUnreachableMemory", "(IZ)Ljava/lang/String;", (void*)android_os_Debug_getUnreachableMemory }, + { "getZramFreeKb", "()J", + (void*)android_os_Debug_getFreeZramKb }, }; int register_android_os_Debug(JNIEnv *env) diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml index 1b691d68a201..c23ca835433e 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 02a9adf4fb4d..bff6b5fb3d24 100644 --- a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java +++ b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java @@ -60,7 +60,8 @@ public class DocumentsProviderTest extends ProviderTestCase2<TestDocumentsProvid 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 03b751c07c6c..eb26367d3d29 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -11,3 +11,6 @@ lajos@google.com 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/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java index e85d99774986..4ea384ac70b2 100644 --- a/media/apex/java/android/media/MediaController2.java +++ b/media/apex/java/android/media/MediaController2.java @@ -317,7 +317,9 @@ public class MediaController2 implements AutoCloseable { isCanceled = !mRequestedCommandSeqNumbers.remove(seq); } if (isCanceled) { - resultReceiver.send(RESULT_INFO_SKIPPED, null); + if (resultReceiver != null) { + resultReceiver.send(RESULT_INFO_SKIPPED, null); + } return; } Session2Command.Result result = mCallback.onSessionCommand( diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java index fdd07fdd52e3..1f8400a7ef66 100644 --- a/media/apex/java/android/media/MediaSession2.java +++ b/media/apex/java/android/media/MediaSession2.java @@ -259,6 +259,20 @@ public class MediaSession2 implements AutoCloseable { } } + /** + * Gets the list of the connected controllers + * + * @return list of the connected controllers. + */ + @NonNull + public List<ControllerInfo> getConnectedControllers() { + List<ControllerInfo> controllers = new ArrayList<>(); + synchronized (mLock) { + controllers.addAll(mConnectedControllers.values()); + } + return controllers; + } + boolean isClosed() { synchronized (mLock) { return mClosed; @@ -317,13 +331,6 @@ public class MediaSession2 implements AutoCloseable { if (DEBUG) { Log.d(TAG, "Accepting connection: " + controllerInfo); } - synchronized (mLock) { - if (mConnectedControllers.containsKey(controller)) { - Log.w(TAG, "Controller " + controllerInfo + " has sent connection" - + " request multiple times"); - } - mConnectedControllers.put(controller, controllerInfo); - } // If connection is accepted, notify the current state to the controller. // It's needed because we cannot call synchronous calls between // session/controller. @@ -339,6 +346,13 @@ public class MediaSession2 implements AutoCloseable { return; } controllerInfo.notifyConnected(connectionResult); + synchronized (mLock) { + if (mConnectedControllers.containsKey(controller)) { + Log.w(TAG, "Controller " + controllerInfo + " has sent connection" + + " request multiple times"); + } + mConnectedControllers.put(controller, controllerInfo); + } connected = true; } finally { if (!connected) { @@ -417,14 +431,6 @@ public class MediaSession2 implements AutoCloseable { controllerInfo.removeRequestedCommandSeqNumber(seq); } - private List<ControllerInfo> getConnectedControllers() { - List<ControllerInfo> controllers = new ArrayList<>(); - synchronized (mLock) { - controllers.addAll(mConnectedControllers.values()); - } - return controllers; - } - /** * Builder for {@link MediaSession2}. * <p> diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java index af71ac534bf7..3414397d73c3 100644 --- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java +++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java @@ -40,9 +40,7 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.SocketKeepalive; -import android.net.TcpKeepalivePacketData; -import android.net.TcpKeepalivePacketData.TcpSocketInfo; +import android.net.TcpKeepalivePacketDataParcelable; import android.net.apf.ApfFilter.ApfConfiguration; import android.net.apf.ApfGenerator.IllegalInstructionException; import android.net.apf.ApfGenerator.Register; @@ -1546,12 +1544,15 @@ public class ApfTest { InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR); InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR); - final TcpSocketInfo v4Tsi = new TcpSocketInfo( - srcAddr, srcPort, dstAddr, dstPort, seqNum, ackNum, window, windowScale); - final TcpKeepalivePacketData ipv4TcpKeepalivePacket = - TcpKeepalivePacketData.tcpKeepalivePacket(v4Tsi); + final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); + parcel.srcAddress = srcAddr.getAddress(); + parcel.srcPort = srcPort; + parcel.dstAddress = dstAddr.getAddress(); + parcel.dstPort = dstPort; + parcel.seq = seqNum; + parcel.ack = ackNum; - apfFilter.addKeepalivePacketFilter(slot1, ipv4TcpKeepalivePacket.toStableParcelable()); + apfFilter.addKeepalivePacketFilter(slot1, parcel); program = cb.getApfProgram(); // Verify IPv4 keepalive ack packet is dropped @@ -1580,11 +1581,17 @@ public class ApfTest { // dst: 2404:0:0:0:0:0:faf2, port: 54321 srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR); dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR); - final TcpSocketInfo v6Tsi = new TcpSocketInfo( - srcAddr, srcPort, dstAddr, dstPort, seqNum, ackNum, window, windowScale); - final TcpKeepalivePacketData ipv6TcpKeepalivePacket = - TcpKeepalivePacketData.tcpKeepalivePacket(v6Tsi); - apfFilter.addKeepalivePacketFilter(slot1, ipv6TcpKeepalivePacket.toStableParcelable()); + + final TcpKeepalivePacketDataParcelable ipv6Parcel = + new TcpKeepalivePacketDataParcelable(); + ipv6Parcel.srcAddress = srcAddr.getAddress(); + ipv6Parcel.srcPort = srcPort; + ipv6Parcel.dstAddress = dstAddr.getAddress(); + ipv6Parcel.dstPort = dstPort; + ipv6Parcel.seq = seqNum; + ipv6Parcel.ack = ackNum; + + apfFilter.addKeepalivePacketFilter(slot1, ipv6Parcel); program = cb.getApfProgram(); // Verify IPv6 keepalive ack packet is dropped @@ -1606,8 +1613,8 @@ public class ApfTest { apfFilter.removeKeepalivePacketFilter(slot1); // Verify multiple filters - apfFilter.addKeepalivePacketFilter(slot1, ipv4TcpKeepalivePacket.toStableParcelable()); - apfFilter.addKeepalivePacketFilter(slot2, ipv6TcpKeepalivePacket.toStableParcelable()); + apfFilter.addKeepalivePacketFilter(slot1, parcel); + apfFilter.addKeepalivePacketFilter(slot2, ipv6Parcel); program = cb.getApfProgram(); // Verify IPv4 keepalive ack packet is dropped @@ -1643,7 +1650,7 @@ public class ApfTest { // Remove keepalive filters apfFilter.removeKeepalivePacketFilter(slot1); apfFilter.removeKeepalivePacketFilter(slot2); - } catch (SocketKeepalive.InvalidPacketException e) { + } catch (UnsupportedOperationException e) { // TODO: support V6 packets } diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index e0d178fb9a1e..29ae1b29792b 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -137,6 +137,7 @@ android_app { static_libs: [ "SystemUI-core", ], + resource_dirs: [], platform_apis: true, product_specific: true, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java index 6177344a3ef4..5c8071885c0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java @@ -24,9 +24,11 @@ import android.graphics.PixelFormat; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.ImageReader; +import android.os.SystemClock; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; +import android.util.Log; import android.view.Display; import android.view.DisplayInfo; @@ -39,12 +41,15 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.function.Predicate; + /** atest NavigationBarButtonTest */ @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest public class NavigationBarButtonTest extends SysuiTestCase { + private static final String TAG = "NavigationBarButtonTest"; private ImageReader mReader; private NavigationBarView mNavBar; private VirtualDisplay mVirtualDisplay; @@ -78,9 +83,31 @@ public class NavigationBarButtonTest extends SysuiTestCase { assertNotNull("virtual display must not be null", mVirtualDisplay); + waitForDisplayReady(mVirtualDisplay.getDisplay().getDisplayId()); + return mVirtualDisplay.getDisplay(); } + private void waitForDisplayReady(int displayId) { + waitForDisplayCondition(displayId, state -> state); + } + + private void waitForDisplayCondition(int displayId, Predicate<Boolean> condition) { + for (int retry = 1; retry <= 10; retry++) { + if (condition.test(isDisplayOn(displayId))) { + return; + } + Log.i(TAG, "Waiting for virtual display ready ... retry = " + retry); + SystemClock.sleep(500); + } + } + + private boolean isDisplayOn(int displayId) { + DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); + Display display = displayManager.getDisplay(displayId); + return display != null && display.getState() == Display.STATE_ON; + } + @After public void tearDown() { releaseDisplay(); diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index d4ac731f8810..32e2cacbb37b 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -70,6 +70,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -1484,19 +1485,50 @@ public class UserBackupManagerService { } /** - * Clear an application's data, blocking until the operation completes or times out. If {@code - * keepSystemState} is {@code true}, we intentionally do not clear system state that would - * ordinarily also be cleared, because we aren't actually wiping the app back to empty; we're - * bringing it into the actual expected state related to the already-restored notification state - * etc. + * Clear an application's data after a failed restore, blocking until the operation completes or + * times out. */ - public void clearApplicationDataSynchronous(String packageName, boolean keepSystemState) { - // Don't wipe packages marked allowClearUserData=false + public void clearApplicationDataAfterRestoreFailure(String packageName) { + clearApplicationDataSynchronous(packageName, true, false); + } + + /** + * Clear an application's data before restore, blocking until the operation completes or times + * out. + */ + public void clearApplicationDataBeforeRestore(String packageName) { + clearApplicationDataSynchronous(packageName, false, true); + } + + /** + * Clear an application's data, blocking until the operation completes or times out. + * + * @param checkFlagAllowClearUserDataOnFailedRestore if {@code true} uses + * {@link ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE} to decide if + * clearing data is allowed after a failed restore. + * + * @param keepSystemState if {@code true}, we don't clear system state such as already restored + * notification settings, permission grants, etc. + */ + private void clearApplicationDataSynchronous(String packageName, + boolean checkFlagAllowClearUserDataOnFailedRestore, boolean keepSystemState) { try { - PackageInfo info = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId); - if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) { + ApplicationInfo applicationInfo = mPackageManager.getPackageInfoAsUser( + packageName, 0, mUserId).applicationInfo; + + boolean shouldClearData; + if (checkFlagAllowClearUserDataOnFailedRestore + && applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) { + shouldClearData = (applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE) != 0; + } else { + shouldClearData = + (applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) != 0; + } + + if (!shouldClearData) { if (MORE_DEBUG) { - Slog.i(TAG, "allowClearUserData=false so not wiping " + Slog.i(TAG, "Clearing app data is not allowed so not wiping " + packageName); } return; @@ -1511,8 +1543,8 @@ public class UserBackupManagerService { synchronized (mClearDataLock) { mClearingData = true; try { - mActivityManager.clearApplicationUserData( - packageName, keepSystemState, observer, mUserId); + mActivityManager.clearApplicationUserData(packageName, keepSystemState, observer, + mUserId); } catch (RemoteException e) { // can't happen because the activity manager is in this process } diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index c5389fa5f878..836a5e883c62 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -352,7 +352,7 @@ public class FullRestoreEngine extends RestoreEngine { Slog.d(TAG, "Clearing app data preparatory to full restore"); } - mBackupManagerService.clearApplicationDataSynchronous(pkg, true); + mBackupManagerService.clearApplicationDataBeforeRestore(pkg); } else { if (MORE_DEBUG) { Slog.d(TAG, "backup agent (" 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 324c2d974010..8160e04d6865 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -988,8 +988,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // We also need to wipe the current target's data, as it's probably // in an incoherent state. - backupManagerService.clearApplicationDataSynchronous( - mCurrentPackage.packageName, false); + backupManagerService.clearApplicationDataAfterRestoreFailure( + mCurrentPackage.packageName); // Schedule the next state based on the nature of our failure if (status == BackupTransport.TRANSPORT_ERROR) { @@ -1114,7 +1114,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // 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.clearApplicationDataSynchronous(mCurrentPackage.packageName, false); + backupManagerService.clearApplicationDataAfterRestoreFailure(mCurrentPackage.packageName); keyValueAgentCleanup(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2f20572caa99..3c0430fe0adf 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 class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } }, 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } @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 @@ public class ActivityManagerService extends IActivityManager.Stub | 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } 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/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java index c7e4fc78c013..17ffd9c5e093 100644 --- a/services/core/java/com/android/server/am/AppCompactor.java +++ b/services/core/java/com/android/server/am/AppCompactor.java @@ -28,6 +28,7 @@ import static android.provider.DeviceConfig.ActivityManager.KEY_USE_COMPACTION; import android.app.ActivityManager; import android.app.ActivityThread; +import android.os.Debug; import android.os.Handler; import android.os.Message; import android.os.Process; @@ -410,6 +411,7 @@ public final class AppCompactor { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact " + ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full") + ": " + name); + long zramFreeKbBefore = Debug.getZramFreeKb(); long[] rssBefore = Process.getRss(pid); FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim"); fos.write(action.getBytes()); @@ -417,10 +419,12 @@ public final class AppCompactor { long[] rssAfter = Process.getRss(pid); long end = SystemClock.uptimeMillis(); long time = end - start; + long zramFreeKbAfter = Debug.getZramFreeKb(); EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name, action, rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time, - lastCompactAction, lastCompactTime, msg.arg1, msg.arg2); + lastCompactAction, lastCompactTime, msg.arg1, msg.arg2, + zramFreeKbBefore, zramFreeKbAfter); // Note that as above not taking mPhenoTypeFlagLock here to avoid locking // on every single compaction for a flag that will seldom change and the // impact of reading the wrong value here is low. @@ -429,7 +433,8 @@ public final class AppCompactor { rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time, lastCompactAction, lastCompactTime, msg.arg1, - ActivityManager.processStateAmToProto(msg.arg2)); + ActivityManager.processStateAmToProto(msg.arg2), + zramFreeKbBefore, zramFreeKbAfter); } synchronized (mAm) { proc.lastCompactTime = end; diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index a71f6af80bec..4b12e43692a6 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -138,4 +138,4 @@ option java_package com.android.server.am 30061 am_remove_task (Task ID|1|5), (Stack ID|1|5) # The task is being compacted -30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(AfterRssTotal|2|2),(AfterRssFile|2|2),(AfterRssAnon|2|2),(AfterRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2) +30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(AfterRssTotal|2|2),(AfterRssFile|2|2),(AfterRssAnon|2|2),(AfterRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2),(BeforeZRAMFree|2|2),(AfterZRAMFree|2|2) diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index af56352b8cc0..a08c829f0576 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 @@ public final class PendingIntentRecord extends IIntentSender.Stub { // 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 3ea114758498..376999dfd80d 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.Context; 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 @@ public abstract class PreBootBroadcaster extends IIntentReceiver.Stub { 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 7f6648a3d174..ac20f6c7eaaf 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 @@ class UserController implements Handler.Callback { | 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { | 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { } }, 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { } }, 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 @@ class UserController implements Handler.Callback { } 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { 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 @@ class UserController implements Handler.Callback { 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 0e3309088f21..70c28a854512 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.ActivityThread; 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 @@ public class AppOpsService extends IAppOpsService.Stub { @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 @@ public class AppOpsService extends IAppOpsService.Stub { @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 @@ public class AppOpsService extends IAppOpsService.Stub { 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/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java index 5b765dfee3a4..d53d81cf0860 100644 --- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java +++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java @@ -28,7 +28,7 @@ import android.util.ByteStringUtils; import android.util.EventLog; import android.util.Log; -import com.android.server.pm.dex.DexLogger; +import com.android.server.pm.dex.DynamicCodeLogger; import java.util.ArrayList; import java.util.List; @@ -38,9 +38,10 @@ import java.util.regex.Pattern; /** * Scheduled jobs related to logging of app dynamic code loading. The idle logging job runs daily - * while idle and charging and calls {@link DexLogger} to write dynamic code information to the - * event log. The audit watching job scans the event log periodically while idle to find AVC audit - * messages indicating use of dynamic native code and adds the information to {@link DexLogger}. + * while idle and charging and calls {@link DynamicCodeLogger} to write dynamic code information + * to the event log. The audit watching job scans the event log periodically while idle to find AVC + * audit messages indicating use of dynamic native code and adds the information to + * {@link DynamicCodeLogger}. * {@hide} */ public class DynamicCodeLoggingService extends JobService { @@ -130,9 +131,9 @@ public class DynamicCodeLoggingService extends JobService { } } - private static DexLogger getDexLogger() { + private static DynamicCodeLogger getDynamicCodeLogger() { PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package"); - return pm.getDexManager().getDexLogger(); + return pm.getDexManager().getDynamicCodeLogger(); } private class IdleLoggingThread extends Thread { @@ -149,14 +150,14 @@ public class DynamicCodeLoggingService extends JobService { Log.d(TAG, "Starting IdleLoggingJob run"); } - DexLogger dexLogger = getDexLogger(); - for (String packageName : dexLogger.getAllPackagesWithDynamicCodeLoading()) { + DynamicCodeLogger dynamicCodeLogger = getDynamicCodeLogger(); + for (String packageName : dynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()) { if (mIdleLoggingStopRequested) { Log.w(TAG, "Stopping IdleLoggingJob run at scheduler request"); return; } - dexLogger.logDynamicCodeLoading(packageName); + dynamicCodeLogger.logDynamicCodeLoading(packageName); } jobFinished(mParams, /* reschedule */ false); @@ -191,7 +192,7 @@ public class DynamicCodeLoggingService extends JobService { private boolean processAuditEvents() { // Scan the event log for SELinux (avc) audit messages indicating when an // (untrusted) app has executed native code from an app data - // file. Matches are recorded in DexLogger. + // file. Matches are recorded in DynamicCodeLogger. // // These messages come from the kernel audit system via logd. (Note that // some devices may not generate these messages at all, or the format may @@ -213,7 +214,7 @@ public class DynamicCodeLoggingService extends JobService { // On each run we process all the matching events in the log. This may // mean re-processing events we have already seen, and in any case there // may be duplicate events for the same app+file. These are de-duplicated - // by DexLogger. + // by DynamicCodeLogger. // // Note that any app can write a message to the event log, including one // that looks exactly like an AVC audit message, so the information may @@ -228,7 +229,7 @@ public class DynamicCodeLoggingService extends JobService { return true; } - DexLogger dexLogger = getDexLogger(); + DynamicCodeLogger dynamicCodeLogger = getDynamicCodeLogger(); List<EventLog.Event> events = new ArrayList<>(); EventLog.readEvents(tags, events); @@ -267,7 +268,7 @@ public class DynamicCodeLoggingService extends JobService { // hex-encodes the bytes; we need to undo that. path = unhex(matcher.group(2)); } - dexLogger.recordNative(uid, path); + dynamicCodeLogger.recordNative(uid, path); } return true; diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index ee6995b11430..3b805d515178 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -86,11 +86,11 @@ public class DexManager { // encode and save the dex usage data. private final PackageDexUsage mPackageDexUsage; - // DexLogger handles recording of dynamic code loading - which is similar to PackageDexUsage - // but records a different aspect of the data. + // DynamicCodeLogger handles recording of dynamic code loading - which is similar to + // PackageDexUsage but records a different aspect of the data. // (It additionally includes DEX files loaded with unsupported class loaders, and doesn't // record class loaders or ISAs.) - private final DexLogger mDexLogger; + private final DynamicCodeLogger mDynamicCodeLogger; private final IPackageManager mPackageManager; private final PackageDexOptimizer mPackageDexOptimizer; @@ -126,11 +126,11 @@ public class DexManager { mPackageDexOptimizer = pdo; mInstaller = installer; mInstallLock = installLock; - mDexLogger = new DexLogger(pms, installer); + mDynamicCodeLogger = new DynamicCodeLogger(pms, installer); } - public DexLogger getDexLogger() { - return mDexLogger; + public DynamicCodeLogger getDynamicCodeLogger() { + return mDynamicCodeLogger; } /** @@ -230,8 +230,8 @@ public class DexManager { if (!primaryOrSplit) { // Record loading of a DEX file from an app data directory. - mDexLogger.recordDex(loaderUserId, dexPath, searchResult.mOwningPackageName, - loadingAppInfo.packageName); + mDynamicCodeLogger.recordDex(loaderUserId, dexPath, + searchResult.mOwningPackageName, loadingAppInfo.packageName); } if (classLoaderContexts != null) { @@ -269,7 +269,7 @@ public class DexManager { loadInternal(existingPackages); } catch (Exception e) { mPackageDexUsage.clear(); - mDexLogger.clear(); + mDynamicCodeLogger.clear(); Slog.w(TAG, "Exception while loading. Starting with a fresh state.", e); } } @@ -320,12 +320,12 @@ public class DexManager { if (mPackageDexUsage.removePackage(packageName)) { mPackageDexUsage.maybeWriteAsync(); } - mDexLogger.removePackage(packageName); + mDynamicCodeLogger.removePackage(packageName); } else { if (mPackageDexUsage.removeUserPackage(packageName, userId)) { mPackageDexUsage.maybeWriteAsync(); } - mDexLogger.removeUserPackage(packageName, userId); + mDynamicCodeLogger.removeUserPackage(packageName, userId); } } @@ -404,9 +404,9 @@ public class DexManager { } try { - mDexLogger.readAndSync(packageToUsersMap); + mDynamicCodeLogger.readAndSync(packageToUsersMap); } catch (Exception e) { - mDexLogger.clear(); + mDynamicCodeLogger.clear(); Slog.w(TAG, "Exception while loading package dynamic code usage. " + "Starting with a fresh state.", e); } @@ -692,7 +692,7 @@ public class DexManager { */ public void writePackageDexUsageNow() { mPackageDexUsage.writeNow(); - mDexLogger.writeNow(); + mDynamicCodeLogger.writeNow(); } /** diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java index 59cc0cfeef45..2c75bcdaa1ef 100644 --- a/services/core/java/com/android/server/pm/dex/DexLogger.java +++ b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.pm.dex; @@ -44,12 +44,12 @@ import java.util.Map; import java.util.Set; /** - * This class is responsible for logging data about secondary dex files and, despite the name, - * native code executed from an app's private directory. The data logged includes hashes of the - * name and content of each file. + * This class is responsible for logging data about secondary dex files and native code executed + * from an app's private directory. The data logged includes hashes of the name and content of each + * file. */ -public class DexLogger { - private static final String TAG = "DexLogger"; +public class DynamicCodeLogger { + private static final String TAG = "DynamicCodeLogger"; // Event log tag & subtags used for SafetyNet logging of dynamic code loading (DCL) - // see b/63927552. @@ -61,12 +61,12 @@ public class DexLogger { private final PackageDynamicCodeLoading mPackageDynamicCodeLoading; private final Installer mInstaller; - public DexLogger(IPackageManager pms, Installer installer) { + DynamicCodeLogger(IPackageManager pms, Installer installer) { this(pms, installer, new PackageDynamicCodeLoading()); } @VisibleForTesting - DexLogger(IPackageManager pms, Installer installer, + DynamicCodeLogger(IPackageManager pms, Installer installer, PackageDynamicCodeLoading packageDynamicCodeLoading) { mPackageManager = pms; mPackageDynamicCodeLoading = packageDynamicCodeLoading; @@ -217,7 +217,7 @@ public class DexLogger { /** * Record that an app running in the specified uid has executed native code from the file at - * {@link path}. + * {@param path}. */ public void recordNative(int loadingUid, String path) { String[] packages; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 1782b6a8aa78..176dbbf6a965 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -538,6 +538,9 @@ public final class PowerManagerService extends SystemService // True if we are currently in VR Mode. private boolean mIsVrModeEnabled; + // True if we in the process of performing a forceSuspend + private boolean mForceSuspendActive; + private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver { @Override public void onUserSwitching(int newUserId) throws RemoteException {} @@ -684,6 +687,11 @@ public final class PowerManagerService extends SystemService public void nativeSetFeature(int featureId, int data) { PowerManagerService.nativeSetFeature(featureId, data); } + + /** Wrapper for PowerManager.nativeForceSuspend */ + public boolean nativeForceSuspend() { + return PowerManagerService.nativeForceSuspend(); + } } @VisibleForTesting @@ -718,6 +726,7 @@ public final class PowerManagerService extends SystemService private static native void nativeSetAutoSuspend(boolean enable); private static native void nativeSendPowerHint(int hintId, int data); private static native void nativeSetFeature(int featureId, int data); + private static native boolean nativeForceSuspend(); public PowerManagerService(Context context) { this(context, new Injector()); @@ -1427,7 +1436,7 @@ public final class PowerManagerService extends SystemService } if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE - || !mBootCompleted || !mSystemReady) { + || !mBootCompleted || !mSystemReady || mForceSuspendActive) { return false; } @@ -1463,8 +1472,13 @@ public final class PowerManagerService extends SystemService } } - // This method is called goToSleep for historical reasons but we actually start - // dozing before really going to sleep. + /** + * Puts the system in doze. + * + * This method is called goToSleep for historical reasons but actually attempts to DOZE, + * and only tucks itself in to SLEEP if requested with the flag + * {@link PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE}. + */ @SuppressWarnings("deprecation") private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) { if (DEBUG_SPEW) { @@ -1481,35 +1495,10 @@ public final class PowerManagerService extends SystemService Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep"); try { - switch (reason) { - case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN: - Slog.i(TAG, "Going to sleep due to device administration policy " - + "(uid " + uid +")..."); - break; - case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT: - Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")..."); - break; - case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH: - Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")..."); - break; - case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON: - Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")..."); - break; - case PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON: - Slog.i(TAG, "Going to sleep due to sleep button (uid " + uid +")..."); - break; - case PowerManager.GO_TO_SLEEP_REASON_HDMI: - Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")..."); - break; - case PowerManager.GO_TO_SLEEP_REASON_ACCESSIBILITY: - Slog.i(TAG, "Going to sleep by an accessibility service request (uid " - + uid +")..."); - break; - default: - Slog.i(TAG, "Going to sleep by application request (uid " + uid +")..."); - reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION; - break; - } + reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX, + Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN)); + Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason) + + " (uid " + uid + ")..."); mLastSleepTime = eventTime; mLastSleepReason = reason; @@ -3063,10 +3052,10 @@ public final class PowerManagerService extends SystemService if (appid >= Process.FIRST_APPLICATION_UID) { // Cached inactive processes are never allowed to hold wake locks. if (mConstants.NO_CACHED_WAKE_LOCKS) { - disabled = !wakeLock.mUidState.mActive && - wakeLock.mUidState.mProcState + disabled = mForceSuspendActive + || (!wakeLock.mUidState.mActive && wakeLock.mUidState.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT && - wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER; + wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER); } if (mDeviceIdleMode) { // If we are in idle mode, we will also ignore all partial wake locks that are @@ -3241,6 +3230,34 @@ public final class PowerManagerService extends SystemService } } + private boolean forceSuspendInternal(int uid) { + try { + synchronized (mLock) { + mForceSuspendActive = true; + // Place the system in an non-interactive state + goToSleepInternal(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND, + PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid); + + // Disable all the partial wake locks as well + updateWakeLockDisabledStatesLocked(); + } + + Slog.i(TAG, "Force-Suspending (uid " + uid + ")..."); + boolean success = mNativeWrapper.nativeForceSuspend(); + if (!success) { + Slog.i(TAG, "Force-Suspending failed in native."); + } + return success; + } finally { + synchronized (mLock) { + mForceSuspendActive = false; + // Re-enable wake locks once again. + updateWakeLockDisabledStatesLocked(); + } + } + } + /** * Low-level function turn the device off immediately, without trying * to be clean. Most people should use {@link ShutdownThread} for a clean shutdown. @@ -4743,6 +4760,20 @@ public final class PowerManagerService extends SystemService } } + @Override // binder call + public boolean forceSuspend() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final int uid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + return forceSuspendInternal(uid); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + @Override // Binder call protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 423ec4c869c1..c7044a15dd5d 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -366,17 +366,22 @@ public class TrustManagerService extends SystemService { } catch (RemoteException e) { } - if (mSettingsObserver.getTrustAgentsExtendUnlock()) { - trusted = trusted && (!showingKeyguard || isFromUnlock) && userId == mCurrentUser; - if (DEBUG) { - Slog.d(TAG, "Extend unlock setting trusted as " + Boolean.toString(trusted) - + " && " + Boolean.toString(!showingKeyguard) - + " && " + Boolean.toString(userId == mCurrentUser)); - } - } - boolean changed; synchronized (mUserIsTrusted) { + if (mSettingsObserver.getTrustAgentsExtendUnlock()) { + // In extend unlock trust agents can only set the device to trusted if it already + // trusted or the device is unlocked. Attempting to set the device as trusted + // when the device is locked will be ignored. + changed = mUserIsTrusted.get(userId) != trusted; + trusted = trusted + && (!showingKeyguard || isFromUnlock || !changed) + && userId == mCurrentUser; + if (DEBUG) { + Slog.d(TAG, "Extend unlock setting trusted as " + Boolean.toString(trusted) + + " && " + Boolean.toString(!showingKeyguard) + + " && " + Boolean.toString(userId == mCurrentUser)); + } + } changed = mUserIsTrusted.get(userId) != trusted; mUserIsTrusted.put(userId, trusted); } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 6dc73bbb80cb..19ff43822923 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1879,6 +1879,9 @@ public class AppTransition implements Dump { mNextAppTransitionAnimationsSpecsFuture = specsFuture; mNextAppTransitionScaleUp = scaleUp; mNextAppTransitionFutureCallback = callback; + if (isReady()) { + fetchAppTransitionSpecsFromFuture(); + } } } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index ea65dd99077a..1d76a71aaea1 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 @@ public class DockedStackDividerController { 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 @@ public class DockedStackDividerController { } 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 59d7560fc5b0..9d3112fec0f2 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 @@ class TaskRecord extends ConfigurationContainer { 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 7b742fd2e0f3..b91519903eb8 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 @@ public class TaskStack extends WindowContainer<Task> implements } 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/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 9be728bac532..ec7a78beb122 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -295,6 +295,12 @@ static void nativeSetFeature(JNIEnv* /* env */, jclass /* clazz */, jint feature } } +static bool nativeForceSuspend(JNIEnv* /* env */, jclass /* clazz */) { + bool retval = false; + getSuspendControl()->forceSuspend(&retval); + return retval; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gPowerManagerServiceMethods[] = { @@ -303,6 +309,8 @@ static const JNINativeMethod gPowerManagerServiceMethods[] = { (void*) nativeInit }, { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V", (void*) nativeAcquireSuspendBlocker }, + { "nativeForceSuspend", "()Z", + (void*) nativeForceSuspend }, { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V", (void*) nativeReleaseSuspendBlocker }, { "nativeSetInteractive", "(Z)V", diff --git a/services/devicepolicy/TEST_MAPPING b/services/devicepolicy/TEST_MAPPING new file mode 100644 index 000000000000..ab85a6873cf6 --- /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 bd03a8d22643..04abeca1192e 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 @@ public class UserControllerTest { 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/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index 48ab8d6698bd..0196279cbf56 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -568,7 +568,8 @@ public class DexManagerTests { } private PackageDynamicCode getPackageDynamicCodeInfo(TestData testData) { - return mDexManager.getDexLogger().getPackageDynamicCodeInfo(testData.getPackageName()); + return mDexManager.getDynamicCodeLogger() + .getPackageDynamicCodeInfo(testData.getPackageName()); } private void assertNoUseInfo(TestData testData) { diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java index 6da202b93065..7992ba33c8da 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java @@ -53,7 +53,7 @@ import org.mockito.stubbing.Stubber; @RunWith(AndroidJUnit4.class) @SmallTest -public class DexLoggerTests { +public class DynamicCodeLoggerTests { private static final String OWNING_PACKAGE_NAME = "package.name"; private static final String VOLUME_UUID = "volUuid"; private static final String FILE_PATH = "/bar/foo.jar"; @@ -85,7 +85,7 @@ public class DexLoggerTests { @Mock IPackageManager mPM; @Mock Installer mInstaller; - private DexLogger mDexLogger; + private DynamicCodeLogger mDynamicCodeLogger; private final ListMultimap<Integer, String> mMessagesForUid = ArrayListMultimap.create(); private boolean mWriteTriggered = false; @@ -106,7 +106,7 @@ public class DexLoggerTests { }; // For test purposes capture log messages as well as sending to the event log. - mDexLogger = new DexLogger(mPM, mInstaller, packageDynamicCodeLoading) { + mDynamicCodeLogger = new DynamicCodeLogger(mPM, mInstaller, packageDynamicCodeLoading) { @Override void writeDclEvent(String subtag, int uid, String message) { super.writeDclEvent(subtag, uid, message); @@ -131,13 +131,13 @@ public class DexLoggerTests { whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES)); recordLoad(OWNING_PACKAGE_NAME, FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID); assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITH_CONTENT_HASH); assertThat(mWriteTriggered).isFalse(); - assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()) + assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()) .containsExactly(OWNING_PACKAGE_NAME); } @@ -146,14 +146,14 @@ public class DexLoggerTests { whenFileIsHashed(FILE_PATH, doReturn(EMPTY_BYTES)); recordLoad(OWNING_PACKAGE_NAME, FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID); assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH); // File should be removed from the DCL list, since we can't hash it. assertThat(mWriteTriggered).isTrue(); - assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); + assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); } @Test @@ -162,24 +162,24 @@ public class DexLoggerTests { doThrow(new InstallerException("Intentional failure for test"))); recordLoad(OWNING_PACKAGE_NAME, FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID); assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH); // File should be removed from the DCL list, since we can't hash it. assertThat(mWriteTriggered).isTrue(); - assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); + assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); } @Test public void testOneLoader_ownFile_unknownPath() { recordLoad(OWNING_PACKAGE_NAME, "other/path"); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid).isEmpty(); assertThat(mWriteTriggered).isTrue(); - assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); + assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); } @Test @@ -189,7 +189,7 @@ public class DexLoggerTests { setPackageUid(OWNING_PACKAGE_NAME, -1); recordLoad(OWNING_PACKAGE_NAME, filePath); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid).isEmpty(); } @@ -200,7 +200,7 @@ public class DexLoggerTests { setPackageUid("other.package.name", 1001); recordLoad("other.package.name", FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid.keys()).containsExactly(1001); assertThat(mMessagesForUid).containsEntry(1001, EXPECTED_MESSAGE_WITH_CONTENT_HASH); @@ -213,7 +213,7 @@ public class DexLoggerTests { setPackageUid("other.package.name", -1); recordLoad("other.package.name", FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid).isEmpty(); assertThat(mWriteTriggered).isFalse(); @@ -224,14 +224,14 @@ public class DexLoggerTests { whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES)); recordLoadNative(FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID); assertThat(mMessagesForUid) .containsEntry(OWNER_UID, EXPECTED_MESSAGE_NATIVE_WITH_CONTENT_HASH); assertThat(mWriteTriggered).isFalse(); - assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()) + assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()) .containsExactly(OWNING_PACKAGE_NAME); } @@ -247,7 +247,7 @@ public class DexLoggerTests { recordLoad("other.package.name1", otherDexPath); recordLoad("other.package.name2", FILE_PATH); recordLoad(OWNING_PACKAGE_NAME, FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid.keys()).containsExactly(1001, 1001, 1002, OWNER_UID); assertThat(mMessagesForUid).containsEntry(1001, EXPECTED_MESSAGE_WITH_CONTENT_HASH); @@ -256,10 +256,10 @@ public class DexLoggerTests { assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITH_CONTENT_HASH); assertThat(mWriteTriggered).isTrue(); - assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()) + assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()) .containsExactly(OWNING_PACKAGE_NAME); - // Check the DexLogger caching is working + // Check the DynamicCodeLogger caching is working verify(mPM, atMost(1)).getPackageInfo(OWNING_PACKAGE_NAME, /*flags*/ 0, OWNER_USER_ID); } @@ -267,7 +267,7 @@ public class DexLoggerTests { public void testUnknownOwner() { reset(mPM); recordLoad(OWNING_PACKAGE_NAME, FILE_PATH); - mDexLogger.logDynamicCodeLoading("other.package.name"); + mDynamicCodeLogger.logDynamicCodeLoading("other.package.name"); assertThat(mMessagesForUid).isEmpty(); assertThat(mWriteTriggered).isFalse(); @@ -278,11 +278,11 @@ public class DexLoggerTests { public void testUninstalledPackage() { reset(mPM); recordLoad(OWNING_PACKAGE_NAME, FILE_PATH); - mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); + mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME); assertThat(mMessagesForUid).isEmpty(); assertThat(mWriteTriggered).isTrue(); - assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); + assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty(); } private void setPackageUid(String packageName, int uid) throws Exception { @@ -295,7 +295,8 @@ public class DexLoggerTests { } private void recordLoad(String loadingPackageName, String dexPath) { - mDexLogger.recordDex(OWNER_USER_ID, dexPath, OWNING_PACKAGE_NAME, loadingPackageName); + mDynamicCodeLogger.recordDex( + OWNER_USER_ID, dexPath, OWNING_PACKAGE_NAME, loadingPackageName); mWriteTriggered = false; } @@ -304,7 +305,7 @@ public class DexLoggerTests { String[] packageNames = { OWNING_PACKAGE_NAME }; when(mPM.getPackagesForUid(loadingUid)).thenReturn(packageNames); - mDexLogger.recordNative(loadingUid, nativePath); + mDynamicCodeLogger.recordNative(loadingUid, nativePath); mWriteTriggered = false; } } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 63341b6ea38a..911c4a2f4122 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -21,15 +21,21 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.ActivityManagerInternal; +import android.attention.AttentionManagerInternal; import android.content.Context; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.os.BatteryManagerInternal; +import android.os.Binder; import android.os.Looper; import android.os.PowerManager; import android.os.PowerSaveState; @@ -53,6 +59,9 @@ import org.junit.Rule; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.HashMap; +import java.util.Map; + /** * Tests for {@link com.android.server.power.PowerManagerService} */ @@ -67,6 +76,7 @@ public class PowerManagerServiceTest extends AndroidTestCase { private @Mock DisplayManagerInternal mDisplayManagerInternalMock; private @Mock BatteryManagerInternal mBatteryManagerInternalMock; private @Mock ActivityManagerInternal mActivityManagerInternalMock; + private @Mock AttentionManagerInternal mAttentionManagerInternalMock; private @Mock PowerManagerService.NativeWrapper mNativeWrapperMock; private @Mock Notifier mNotifierMock; private PowerManagerService mService; @@ -93,6 +103,7 @@ public class PowerManagerServiceTest extends AndroidTestCase { addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock); addLocalServiceMock(BatteryManagerInternal.class, mBatteryManagerInternalMock); addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock); + addLocalServiceMock(AttentionManagerInternal.class, mAttentionManagerInternalMock); mService = new PowerManagerService(getContext(), new Injector() { Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, @@ -210,4 +221,80 @@ public class PowerManagerServiceTest extends AndroidTestCase { mService.onUserActivity(); assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse(); } + + @SmallTest + public void testForceSuspend_putsDeviceToSleep() { + mService.systemReady(null); + mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); + + // Verify that we start awake + assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + + // Grab the wakefulness value when PowerManager finally calls into the + // native component to actually perform the suspend. + when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> { + assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + return true; + }); + + boolean retval = mService.getBinderServiceInstance().forceSuspend(); + assertThat(retval).isTrue(); + + // Still asleep when the function returns. + assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + } + + @SmallTest + public void testForceSuspend_pakeLocksDisabled() { + final String tag = "TestWakelockTag_098213"; + final int flags = PowerManager.PARTIAL_WAKE_LOCK; + final String pkg = getContext().getOpPackageName(); + + // Set up the Notification mock to keep track of the wakelocks that are currently + // active or disabled. We'll use this to verify that wakelocks are disabled when + // they should be. + final Map<String, Integer> wakelockMap = new HashMap<>(1); + doAnswer(inv -> { + wakelockMap.put((String) inv.getArguments()[1], (int) inv.getArguments()[0]); + return null; + }).when(mNotifierMock).onWakeLockAcquired(anyInt(), anyString(), anyString(), anyInt(), + anyInt(), any(), any()); + doAnswer(inv -> { + wakelockMap.remove((String) inv.getArguments()[1]); + return null; + }).when(mNotifierMock).onWakeLockReleased(anyInt(), anyString(), anyString(), anyInt(), + anyInt(), any(), any()); + + // + // TEST STARTS HERE + // + mService.systemReady(null); + mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); + + // Verify that we start awake + assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + + // Create a wakelock + mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg, + null /* workSource */, null /* historyTag */); + assertThat(wakelockMap.get(tag)).isEqualTo(flags); // Verify wakelock is active. + + // Confirm that the wakelocks have been disabled when the forceSuspend is in flight. + when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> { + // Verify that the wakelock is disabled by the time we get to the native force + // suspend call. + assertThat(wakelockMap.containsKey(tag)).isFalse(); + return true; + }); + + assertThat(mService.getBinderServiceInstance().forceSuspend()).isTrue(); + assertThat(wakelockMap.get(tag)).isEqualTo(flags); + + } + + @SmallTest + public void testForceSuspend_forceSuspendFailurePropogated() { + when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false); + assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse(); + } } 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 bcf9dd218835..388f98ffe4a3 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.Intent.FLAG_ACTIVITY_TASK_ON_HOME; 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 @@ public class TaskRecordTests extends ActivityTestsBase { 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/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java index e92cc56322eb..1cf960a4faba 100644 --- a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java +++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java @@ -49,13 +49,13 @@ import java.util.List; import java.util.concurrent.TimeUnit; /** - * Integration tests for {@link com.android.server.pm.dex.DexLogger}. + * Integration tests for {@link DynamicCodeLogger}, formerly known as {@code DexLogger}. * * The setup for the test dynamically loads code in a jar extracted * from our assets (a secondary dex file). * * We then use shell commands to trigger dynamic code logging (and wait - * for it to complete). This causes DexLogger to log the hash of the + * for it to complete). This causes DynamicCodeLogger to log the hash of the * file's name and content. We verify that this message appears in * the event log. * @@ -99,7 +99,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_standardClassLoader() throws Exception { + public void testGeneratesEvents_standardClassLoader() throws Exception { File privateCopyFile = privateFile("copied.jar"); // Obtained via "echo -n copied.jar | sha256sum" String expectedNameHash = @@ -121,7 +121,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_unknownClassLoader() throws Exception { + public void testGeneratesEvents_unknownClassLoader() throws Exception { File privateCopyFile = privateFile("copied2.jar"); String expectedNameHash = "202158B6A3169D78F1722487205A6B036B3F2F5653FDCFB4E74710611AC7EB93"; @@ -143,7 +143,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_nativeLibrary() throws Exception { + public void testGeneratesEvents_nativeLibrary() throws Exception { File privateCopyFile = privateFile("copied.so"); String expectedNameHash = "996223BAD4B4FE75C57A3DEC61DB9C0B38E0A7AD479FC95F33494F4BC55A0F0E"; @@ -164,7 +164,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_nativeLibrary_escapedName() throws Exception { + public void testGeneratesEvents_nativeLibrary_escapedName() throws Exception { // A file name with a space will be escaped in the audit log; verify we un-escape it // correctly. File privateCopyFile = privateFile("second copy.so"); @@ -187,7 +187,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_nativeExecutable() throws Exception { + public void testGeneratesEvents_nativeExecutable() throws Exception { File privateCopyFile = privateFile("test_executable"); String expectedNameHash = "3FBEC3F925A132D18F347F11AE9A5BB8DE1238828F8B4E064AA86EB68BD46DCF"; @@ -211,7 +211,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_spoofed_validFile() throws Exception { + public void testGeneratesEvents_spoofed_validFile() throws Exception { File privateCopyFile = privateFile("spoofed"); String expectedContentHash = @@ -239,7 +239,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_spoofed_pathTraversal() throws Exception { + public void testGeneratesEvents_spoofed_pathTraversal() throws Exception { File privateDir = privateFile("x").getParentFile(); // Transform /a/b/c -> /a/b/c/../../.. so we get back to the root @@ -276,7 +276,7 @@ public final class DexLoggerIntegrationTests { } @Test - public void testDexLoggerGeneratesEvents_spoofed_otherAppFile() throws Exception { + public void testGeneratesEvents_spoofed_otherAppFile() throws Exception { File ourPath = sContext.getDatabasePath("android_pay"); File targetPath = new File(ourPath.toString() .replace("com.android.frameworks.dexloggertest", "com.google.android.gms")); diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk index 40d4eff53577..0967ad3767c6 100644 --- a/tests/RollbackTest/Android.mk +++ b/tests/RollbackTest/Android.mk @@ -71,7 +71,7 @@ ROLLBACK_TEST_APP_BV2 := $(LOCAL_INSTALLED_MODULE) # 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 @@ LOCAL_JAVA_RESOURCE_FILES := \ $(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 000000000000..c0b718a3e2c1 --- /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 adbad56cd934..ac39f853656a 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 index e57a768ad1b5..e57a768ad1b5 100644 --- a/tests/RollbackTest/AndroidManifest.xml +++ b/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 index ddcf1dabcafc..ddcf1dabcafc 100644 --- a/tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java +++ b/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 index e10f866c899f..e10f866c899f 100644 --- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java +++ b/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 index f07ae9f65b1b..f3edf09c5e95 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.Context; 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.runner.RunWith; 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 @@ public class RollbackTest { } } - // 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 @@ public class RollbackTest { } } - // 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 @@ public class RollbackTest { 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/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java index 60c7a59d9456..280ee1d1c576 100644 --- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java @@ -16,19 +16,31 @@ 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. @@ -157,20 +169,28 @@ class RollbackTestUtils { /** * 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. */ - static void installMultiPackage(boolean enableRollback, String... resourceNames) - throws InterruptedException, IOException { + 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? @@ -183,6 +203,9 @@ class RollbackTestUtils { PackageInstaller.Session session = null; PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); + if (staged) { + params.setStaged(); + } if (enableRollback) { params.setEnableRollback(); } @@ -204,6 +227,36 @@ class RollbackTestUtils { // 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) { @@ -219,4 +272,104 @@ class RollbackTestUtils { .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 000000000000..297bf869278f --- /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 000000000000..2750d3765c20 --- /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 000000000000..6cb0dd091392 --- /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"); + } +} |