Merge "Add WatchdogRollbackOccurred atom"
diff --git a/Android.bp b/Android.bp
index a5cc89c..d4a04cc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -726,7 +726,7 @@
"ext",
],
- jarjar_rules: ":framework-hidl-jarjar",
+ jarjar_rules: "jarjar_rules_hidl.txt",
static_libs: [
"apex_aidl_interface-java",
@@ -738,6 +738,15 @@
"android.hardware.cas-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hardware.health-V1.0-java-constants",
+ "android.hardware.radio-V1.0-java",
+ "android.hardware.radio-V1.1-java",
+ "android.hardware.radio-V1.2-java",
+ "android.hardware.radio-V1.3-java",
+ "android.hardware.radio-V1.4-java",
+ "android.hardware.radio.config-V1.0-java",
+ "android.hardware.radio.config-V1.1-java",
+ "android.hardware.radio.config-V1.2-java",
+ "android.hardware.radio.deprecated-V1.0-java",
"android.hardware.thermal-V1.0-java-constants",
"android.hardware.thermal-V1.0-java",
"android.hardware.thermal-V1.1-java",
@@ -746,15 +755,12 @@
"android.hardware.usb-V1.0-java-constants",
"android.hardware.usb-V1.1-java-constants",
"android.hardware.usb-V1.2-java-constants",
+ "android.hardware.usb.gadget-V1.0-java",
"android.hardware.vibrator-V1.0-java",
"android.hardware.vibrator-V1.1-java",
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.hardware.wifi-V1.0-java-constants",
- "android.hardware.radio-V1.0-java",
- "android.hardware.radio-V1.3-java",
- "android.hardware.radio-V1.4-java",
- "android.hardware.usb.gadget-V1.0-java",
"networkstack-aidl-interfaces-java",
"netd_aidl_interface-java",
"devicepolicyprotosnano",
@@ -788,11 +794,6 @@
],
}
-filegroup {
- name: "framework-hidl-jarjar",
- srcs: ["jarjar_rules_hidl.txt"],
-}
-
java_library {
name: "framework",
defaults: ["framework-defaults"],
diff --git a/api/current.txt b/api/current.txt
index bb6dbeb..124ad58 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5101,7 +5101,7 @@
}
public class KeyguardManager {
- method public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
+ method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method @Deprecated public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -13947,8 +13947,6 @@
@AnyThread public abstract class ColorSpace {
method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[]);
method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[], @NonNull android.graphics.ColorSpace.Adaptation);
- method @NonNull @Size(3) public static float[] cctToIlluminantdXyz(@IntRange(from=1) int);
- method @NonNull @Size(9) public static float[] chromaticAdaptation(@NonNull android.graphics.ColorSpace.Adaptation, @NonNull @Size(min=2, max=3) float[], @NonNull @Size(min=2, max=3) float[]);
method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace);
method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace.RenderIntent);
method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace);
@@ -16498,6 +16496,7 @@
ctor public BiometricPrompt.Builder(android.content.Context);
method public android.hardware.biometrics.BiometricPrompt build();
method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence);
+ method public android.hardware.biometrics.BiometricPrompt.Builder setEnableFallback(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence);
@@ -44662,6 +44661,7 @@
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
+ method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method public android.os.Bundle getCarrierConfigValues();
@@ -48568,6 +48568,7 @@
method public String getName();
method @Deprecated public int getOrientation();
method @Deprecated public int getPixelFormat();
+ method @Nullable public android.graphics.ColorSpace getPreferredWideGamutColorSpace();
method public long getPresentationDeadlineNanos();
method public void getRealMetrics(android.util.DisplayMetrics);
method public void getRealSize(android.graphics.Point);
diff --git a/api/system-current.txt b/api/system-current.txt
index 30d42a23..31e6c6c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1303,13 +1303,13 @@
field public static final String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
- field public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
field public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
+ field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
field public static final String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
@@ -1695,18 +1695,17 @@
public final class RollbackInfo implements android.os.Parcelable {
method public int describeContents();
+ method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
method public int getRollbackId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
- field public final android.content.rollback.PackageRollbackInfo targetPackage;
}
public final class RollbackManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void executeRollback(@NonNull android.content.rollback.RollbackInfo, @NonNull android.content.IntentSender);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(@NonNull android.content.rollback.RollbackInfo, @NonNull android.content.IntentSender);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @Nullable public android.content.rollback.RollbackInfo getAvailableRollback(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
}
@@ -5534,7 +5533,6 @@
method @Deprecated public final void attachBaseContext(android.content.Context);
method @Deprecated public final android.os.IBinder onBind(android.content.Intent);
method @Deprecated public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String);
- method @Deprecated public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String);
field @Deprecated public static final String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8642715..ac99817 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -163,7 +163,7 @@
// Consider removing this if it becomes a problem
ServiceStateChanged service_state_changed = 99;
ServiceLaunchReported service_launch_reported = 100;
- PhenotypeFlagStateChanged phenotype_flag_state_changed = 101;
+ FlagFlipUpdateOccurred flag_flip_update_occurred = 101;
BinaryPushStateChanged binary_push_state_changed = 102;
DevicePolicyEvent device_policy_event = 103;
DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104;
@@ -2498,18 +2498,14 @@
}
/*
- * Logs when a flag flip state changes.
- * Logged in P/h.
+ * Logs when a flag flip update occurrs. Used for mainline modules that update via flag flips.
*/
-message PhenotypeFlagStateChanged {
- // Mendel configuration name.
- optional string mendel_config_name = 1;
- // State
- enum State {
- STATE_UNKNOWN = 0;
- COMMITTED = 1;
- }
- optional State state = 2;
+message FlagFlipUpdateOccurred {
+ // If the event is from a flag config package, specify the package name.
+ optional string flag_flip_package_name = 1;
+
+ // The order id of the package
+ optional int64 order_id = 2;
}
/*
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 181acce..f522d71 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -29,6 +29,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.hardware.biometrics.BiometricPrompt;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -87,6 +88,12 @@
"android.app.action.CONFIRM_FRP_CREDENTIAL";
/**
+ * @hide
+ */
+ public static final String EXTRA_BIOMETRIC_PROMPT_BUNDLE =
+ "android.app.extra.BIOMETRIC_PROMPT_BUNDLE";
+
+ /**
* A CharSequence dialog title to show to the user when used with a
* {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
* @hide
@@ -101,12 +108,6 @@
public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
/**
- * A boolean value to forward to {@link android.hardware.biometrics.BiometricPrompt}.
- * @hide
- */
- public static final String EXTRA_USE_IMPLICIT = "android.app.extra.USE_IMPLICIT";
-
- /**
* A CharSequence description to show to the user on the alternate button when used with
* {@link #ACTION_CONFIRM_FRP_CREDENTIAL}.
* @hide
@@ -124,44 +125,23 @@
public static final int RESULT_ALTERNATE = 1;
/**
- * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
- * for the current user of the device. The caller is expected to launch this activity using
- * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
+ * @deprecated see {@link BiometricPrompt.Builder#setEnableFallback(boolean)}
+ *
+ * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
+ * if enrolled) for the current user of the device. The caller is expected to launch this
+ * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
* {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
*
- * @param title Title to be shown on the dialog.
- * @param description Description to be shown on the dialog.
* @return the intent for launching the activity or null if no password is required.
**/
+ @Deprecated
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
- public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
- return createConfirmDeviceCredentialIntent(title, description, false /* useImplicit */);
- }
-
- /**
- * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
- * for the current user of the device. The caller is expected to launch this activity using
- * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
- * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
- *
- * @param title Title to be shown on the dialog.
- * @param description Description to be shown on the dialog.
- * @param useImplicit If useImplicit is set to true, ConfirmDeviceCredentials will invoke
- * {@link android.hardware.biometrics.BiometricPrompt} with
- * {@link android.hardware.biometrics.BiometricPrompt.Builder#setRequireConfirmation(
- * boolean)} set to false.
- * @return the intent for launching the activity or null if no password is required.
- * @hide
- */
- public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description,
- boolean useImplicit) {
- if (!isDeviceSecure()) {
- return null;
- }
+ public Intent createConfirmDeviceCredentialIntent(CharSequence title,
+ CharSequence description) {
+ if (!isDeviceSecure()) return null;
Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
intent.putExtra(EXTRA_TITLE, title);
intent.putExtra(EXTRA_DESCRIPTION, description);
- intent.putExtra(EXTRA_USE_IMPLICIT, useImplicit);
// explicitly set the package for security
intent.setPackage(getSettingsPackageForIntent(intent));
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 6704a45..47a4a2d 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -87,6 +87,7 @@
* <p>For more information about using a ContentResolver with content providers, read the
* <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
* developer guide.</p>
+ * </div>
*/
public abstract class ContentResolver implements ContentInterface {
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9e7aaf6..22f73db 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2375,8 +2375,7 @@
public static final String ACTION_PACKAGE_ENABLE_ROLLBACK =
"android.intent.action.PACKAGE_ENABLE_ROLLBACK";
/**
- * Broadcast Action: An existing version of an application package has been
- * rolled back to a previous version.
+ * Broadcast Action: A rollback has been committed.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -2385,8 +2384,8 @@
*/
@SystemApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED =
- "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
+ public static final String ACTION_ROLLBACK_COMMITTED =
+ "android.intent.action.ROLLBACK_COMMITTED";
/**
* @hide
* Broadcast Action: Ask system services if there is any reason to
diff --git a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
index 2faf3ad..4f4c34b 100644
--- a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
+++ b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
@@ -27,5 +27,4 @@
*/
oneway interface IRuntimePermissionPresenter {
void getAppPermissions(String packageName, in RemoteCallback callback);
- void revokeRuntimePermission(String packageName, String permissionName);
}
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 420bcb6..63d75a0 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -17,17 +17,13 @@
package android.content.rollback;
import android.content.pm.ParceledListSlice;
-import android.content.pm.StringParceledListSlice;
import android.content.rollback.RollbackInfo;
import android.content.IntentSender;
/** {@hide} */
interface IRollbackManager {
- RollbackInfo getAvailableRollback(String packageName);
-
- StringParceledListSlice getPackagesWithAvailableRollbacks();
-
+ ParceledListSlice getAvailableRollbacks();
ParceledListSlice getRecentlyExecutedRollbacks();
void executeRollback(in RollbackInfo rollback, String callerPackageName,
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 0803a7c..8532b5a 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -20,6 +20,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.List;
+
/**
* Information about a set of packages that can be, or already have been
* rolled back together.
@@ -34,25 +36,20 @@
*/
private final int mRollbackId;
- /**
- * The package that needs to be rolled back.
- */
- public final PackageRollbackInfo targetPackage;
+ private final List<PackageRollbackInfo> mPackages;
- // TODO: Add a list of additional packages rolled back due to atomic
- // install dependencies when rollback of atomic installs is supported.
// TODO: Add a flag to indicate if reboot is required, when rollback of
// staged installs is supported.
/** @hide */
- public RollbackInfo(int rollbackId, PackageRollbackInfo targetPackage) {
+ public RollbackInfo(int rollbackId, List<PackageRollbackInfo> packages) {
this.mRollbackId = rollbackId;
- this.targetPackage = targetPackage;
+ this.mPackages = packages;
}
private RollbackInfo(Parcel in) {
mRollbackId = in.readInt();
- targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in);
+ mPackages = in.createTypedArrayList(PackageRollbackInfo.CREATOR);
}
/**
@@ -62,6 +59,13 @@
return mRollbackId;
}
+ /**
+ * Returns the list of package that are rolled back.
+ */
+ public List<PackageRollbackInfo> getPackages() {
+ return mPackages;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -70,7 +74,7 @@
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mRollbackId);
- targetPackage.writeToParcel(out, flags);
+ out.writeTypedList(mPackages);
}
public static final Parcelable.Creator<RollbackInfo> CREATOR =
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index c1c0bc1..2566ac5 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -17,7 +17,6 @@
package android.content.rollback;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -50,55 +49,26 @@
}
/**
- * Returns the rollback currently available to be executed for the given
- * package.
- * <p>
- * The returned RollbackInfo describes what packages would be rolled back,
- * including package version codes before and after rollback. The rollback
- * can be initiated using {@link #executeRollback(RollbackInfo,IntentSender)}.
- * <p>
- * TODO: What if there is no package installed on device for packageName?
+ * Returns a list of all currently available rollbacks.
*
- * @param packageName name of the package to get the availble RollbackInfo for.
- * @return the rollback available for the package, or null if no rollback
- * is available for the package.
* @throws SecurityException if the caller does not have the
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public @Nullable RollbackInfo getAvailableRollback(@NonNull String packageName) {
+ public List<RollbackInfo> getAvailableRollbacks() {
try {
- return mBinder.getAvailableRollback(packageName);
+ return mBinder.getAvailableRollbacks().getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Gets the names of packages that are available for rollback.
- * Call {@link #getAvailableRollback(String)} to get more information
- * about the rollback available for a particular package.
- *
- * @return the names of packages that are available for rollback.
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
- */
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public @NonNull List<String> getPackagesWithAvailableRollbacks() {
- try {
- return mBinder.getPackagesWithAvailableRollbacks().getList();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
-
- /**
- * Gets the list of all recently executed rollbacks.
+ * Gets the list of all recently committed rollbacks.
* This is for the purposes of preventing re-install of a bad version of a
- * package.
+ * package and monitoring the status of a staged rollback.
* <p>
- * Returns an empty list if there are no recently executed rollbacks.
+ * Returns an empty list if there are no recently committed rollbacks.
* <p>
* To avoid having to keep around complete rollback history forever on a
* device, the returned list of rollbacks is only guaranteed to include
@@ -107,12 +77,12 @@
* (without the possibility of rollback) to a higher version code than was
* rolled back from.
*
- * @return the recently executed rollbacks
+ * @return the recently committed rollbacks
* @throws SecurityException if the caller does not have the
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public @NonNull List<RollbackInfo> getRecentlyExecutedRollbacks() {
+ public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
try {
return mBinder.getRecentlyExecutedRollbacks().getList();
} catch (RemoteException e) {
@@ -121,25 +91,24 @@
}
/**
- * Execute the given rollback, rolling back all versions of the packages
- * to the last good versions previously installed on the device as
- * specified in the given rollback object. The rollback will fail if any
- * of the installed packages or available rollbacks are inconsistent with
- * the versions specified in the given rollback object, which can happen
- * if a package has been updated or a rollback expired since the rollback
- * object was retrieved from {@link #getAvailableRollback(String)}.
+ * Commit the rollback with given id, rolling back all versions of the
+ * packages to the last good versions previously installed on the device
+ * as specified in the corresponding RollbackInfo object. The
+ * rollback will fail if any of the installed packages or available
+ * rollbacks are inconsistent with the versions specified in the given
+ * rollback object, which can happen if a package has been updated or a
+ * rollback expired since the rollback object was retrieved from
+ * {@link #getAvailableRollbacks()}.
* <p>
* TODO: Specify the returns status codes.
- * TODO: What happens in case reboot is required for the rollback to take
- * effect for staged installs?
*
- * @param rollback to execute
+ * @param rollback to commit
* @param statusReceiver where to deliver the results
* @throws SecurityException if the caller does not have the
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public void executeRollback(@NonNull RollbackInfo rollback,
+ public void commitRollback(@NonNull RollbackInfo rollback,
@NonNull IntentSender statusReceiver) {
try {
mBinder.executeRollback(rollback, mCallerPackageName, statusReceiver);
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 9d37d99..209afb8 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -252,12 +252,55 @@
public static final int FACE_ACQUIRED_TOO_SIMILAR = 15;
/**
+ * The magnitude of the pan angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The pan angle is defined as the angle swept out by the user’s face turning
+ * their neck left and right. The pan angle would be zero if the user faced the
+ * camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ public static final int FACE_ACQUIRED_PAN_TOO_EXTREME = 16;
+
+ /**
+ * The magnitude of the tilt angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The tilt angle is defined as the angle swept out by the user’s face looking up
+ * and down. The pan angle would be zero if the user faced the camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ public static final int FACE_ACQUIRED_TILT_TOO_EXTREME = 17;
+
+ /**
+ * The magnitude of the roll angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The roll angle is defined as the angle swept out by the user’s face tilting their head
+ * towards their shoulders to the left and right. The pan angle would be zero if the user
+ * faced the camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ public static final int FACE_ACQUIRED_ROLL_TOO_EXTREME = 18;
+
+ /**
+ * The user’s face has been obscured by some object.
+ *
+ * The user should be informed to remove any objects from the line of sight from
+ * the sensor to the user’s face.
+ */
+ public static final int FACE_ACQUIRED_FACE_OBSCURED = 19;
+
+ /**
* Hardware vendors may extend this list if there are conditions that do not fall under one of
* the above categories. Vendors are responsible for providing error strings for these errors.
*
* @hide
*/
- public static final int FACE_ACQUIRED_VENDOR = 16;
+ public static final int FACE_ACQUIRED_VENDOR = 20;
/**
* @hide
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 8aac1bf..5afe1a9 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -171,5 +171,39 @@
Slog.w(TAG, "resetTimeout(): Service not connected");
}
}
+
+ /**
+ * TODO(b/123378871): Remove when moved.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void onConfirmDeviceCredentialSuccess() {
+ if (mService != null) {
+ try {
+ mService.onConfirmDeviceCredentialSuccess();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "onConfirmDeviceCredentialSuccess(): Service not connected");
+ }
+ }
+
+ /**
+ * TODO(b/123378871): Remove when moved.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void onConfirmDeviceCredentialError(int error, String message) {
+ if (mService != null) {
+ try {
+ mService.onConfirmDeviceCredentialError(error, message);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected");
+ }
+ }
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index c69b68e4..ec62aba 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -77,6 +77,10 @@
* @hide
*/
public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation";
+ /**
+ * @hide
+ */
+ public static final String KEY_ENABLE_FALLBACK = "enable_fallback";
/**
* Error/help message will show for this amount of time.
@@ -242,6 +246,18 @@
}
/**
+ * The user will first be prompted to authenticate with biometrics, but also given the
+ * option to authenticate with their device PIN, pattern, or password.
+ * @param enable When true, the prompt will fall back to ask for the user's device
+ * credentials (PIN, pattern, or password).
+ * @return
+ */
+ public Builder setEnableFallback(boolean enable) {
+ mBundle.putBoolean(KEY_ENABLE_FALLBACK, enable);
+ return this;
+ }
+
+ /**
* Creates a {@link BiometricPrompt}.
* @return a {@link BiometricPrompt}
* @throws IllegalArgumentException if any of the required fields are not set.
@@ -250,11 +266,15 @@
final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE);
+ final boolean enableFallback = mBundle.getBoolean(KEY_ENABLE_FALLBACK);
if (TextUtils.isEmpty(title) && !useDefaultTitle) {
throw new IllegalArgumentException("Title must be set and non-empty");
- } else if (TextUtils.isEmpty(negative)) {
+ } else if (TextUtils.isEmpty(negative) && !enableFallback) {
throw new IllegalArgumentException("Negative text must be set and non-empty");
+ } else if (!TextUtils.isEmpty(negative) && enableFallback) {
+ throw new IllegalArgumentException("Can't have both negative button behavior"
+ + " and fallback enabled");
}
return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
}
@@ -514,6 +534,9 @@
if (callback == null) {
throw new IllegalArgumentException("Must supply a callback");
}
+ if (mBundle.getBoolean(KEY_ENABLE_FALLBACK)) {
+ throw new IllegalArgumentException("Fallback not supported with crypto");
+ }
authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
}
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index de828f2..e4336d1 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -51,4 +51,12 @@
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetTimeout(in byte [] token);
+
+ // TODO(b/123378871): Remove when moved.
+ // CDCA needs to send results to BiometricService if it was invoked using BiometricPrompt's
+ // setEnableFallback method, since there's no way for us to intercept onActivityResult.
+ // CDCA is launched from BiometricService (startActivityAsUser) instead of *ForResult.
+ void onConfirmDeviceCredentialSuccess();
+ // TODO(b/123378871): Remove when moved.
+ void onConfirmDeviceCredentialError(int error, String message);
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 7e45441..f3ebd7f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
+import android.graphics.ColorSpace;
import android.graphics.Point;
import android.hardware.display.DisplayManager.DisplayListener;
import android.media.projection.IMediaProjection;
@@ -80,12 +81,20 @@
new ArrayList<DisplayListenerDelegate>();
private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
+ private final ColorSpace mWideColorSpace;
private int[] mDisplayIdCache;
private int mWifiDisplayScanNestCount;
private DisplayManagerGlobal(IDisplayManager dm) {
mDm = dm;
+ try {
+ mWideColorSpace =
+ ColorSpace.get(
+ ColorSpace.Named.values()[mDm.getPreferredWideGamutColorSpaceId()]);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
}
/**
@@ -495,6 +504,17 @@
}
/**
+ * Gets the preferred wide gamut color space for all displays.
+ * The wide gamut color space is returned from composition pipeline
+ * based on hardware capability.
+ *
+ * @hide
+ */
+ public ColorSpace getPreferredWideGamutColorSpace() {
+ return mWideColorSpace;
+ }
+
+ /**
* Sets the global brightness configuration for a given user.
*
* @hide
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index aae8afb..5ea8bd6 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -116,4 +116,9 @@
// Get the minimum brightness curve.
Curve getMinimumBrightnessCurve();
+
+ // Gets the id of the preferred wide gamut color space for all displays.
+ // The wide gamut color space is returned from composition pipeline
+ // based on hardware capability.
+ int getPreferredWideGamutColorSpaceId();
}
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 8d568c8..33795f8 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -78,15 +78,6 @@
public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(
@NonNull String packageName);
- /**
- * Revokes the permission {@code permissionName} for app {@code packageName}
- *
- * @param packageName The package for which to revoke
- * @param permissionName The permission to revoke
- */
- public abstract void onRevokeRuntimePermission(@NonNull String packageName,
- @NonNull String permissionName);
-
@Override
public final IBinder onBind(Intent intent) {
return new IRuntimePermissionPresenter.Stub() {
@@ -99,17 +90,6 @@
obtainMessage(RuntimePermissionPresenterService::getAppPermissions,
RuntimePermissionPresenterService.this, packageName, callback));
}
-
- @Override
- public void revokeRuntimePermission(String packageName, String permissionName) {
- checkNotNull(packageName, "packageName");
- checkNotNull(permissionName, "permissionName");
-
- mHandler.sendMessage(
- obtainMessage(RuntimePermissionPresenterService::onRevokeRuntimePermission,
- RuntimePermissionPresenterService.this, packageName,
- permissionName));
- }
};
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index f58efc9..e3a6bd7 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -26,6 +26,7 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.ColorSpace;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -953,6 +954,24 @@
}
/**
+ * Returns the preferred wide color space of the Display.
+ * The returned wide gamut color space is based on hardware capability and
+ * is preferred by the composition pipeline.
+ * Returns null if the display doesn't support wide color gamut.
+ * {@link Display#isWideColorGamut()}.
+ */
+ @Nullable
+ public ColorSpace getPreferredWideGamutColorSpace() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ if (mDisplayInfo.isWideColorGamut()) {
+ return mGlobal.getPreferredWideGamutColorSpace();
+ }
+ return null;
+ }
+ }
+
+ /**
* Gets the supported color modes of this device.
* @hide
*/
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 863b717..4032a6b8 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -46,10 +46,9 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.Process;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import android.view.Surface.OutOfResourcesException;
@@ -60,6 +59,7 @@
import libcore.util.NativeAllocationRegistry;
import java.io.Closeable;
+import java.nio.ByteBuffer;
/**
* Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -75,7 +75,7 @@
private static final String TAG = "SurfaceControl";
private static native long nativeCreate(SurfaceSession session, String name,
- int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
+ int w, int h, int format, int flags, long parentObject, Parcel metadata)
throws OutOfResourcesException;
private static native long nativeReadFromParcel(Parcel in);
private static native long nativeCopyFromSurfaceControl(long nativeObject);
@@ -182,6 +182,7 @@
private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken,
IBinder toToken);
private static native boolean nativeGetProtectedContentSupport();
+ private static native void nativeSetMetadata(long transactionObj, int key, Parcel data);
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
@@ -413,6 +414,24 @@
}
/**
+ * owner UID.
+ * @hide
+ */
+ public static final int METADATA_OWNER_UID = 1;
+
+ /**
+ * Window type as per {@link WindowManager.LayoutParams}.
+ * @hide
+ */
+ public static final int METADATA_WINDOW_TYPE = 2;
+
+ /**
+ * Task id to allow association between surfaces and task.
+ * @hide
+ */
+ public static final int METADATA_TASK_ID = 3;
+
+ /**
* Builder class for {@link SurfaceControl} objects.
*/
public static class Builder {
@@ -423,8 +442,7 @@
private int mFormat = PixelFormat.OPAQUE;
private String mName;
private SurfaceControl mParent;
- private int mWindowType = -1;
- private int mOwnerUid = -1;
+ private SparseIntArray mMetadata;
/**
* Begin building a SurfaceControl with a given {@link SurfaceSession}.
@@ -455,8 +473,8 @@
throw new IllegalArgumentException(
"Only buffer layers can set a valid buffer size.");
}
- return new SurfaceControl(mSession, mName, mWidth, mHeight, mFormat,
- mFlags, mParent, mWindowType, mOwnerUid);
+ return new SurfaceControl(
+ mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata);
}
/**
@@ -581,23 +599,17 @@
}
/**
- * Set surface metadata.
+ * Sets a metadata int.
*
- * Currently these are window-types as per {@link WindowManager.LayoutParams} and
- * owner UIDs. Child surfaces inherit their parents
- * metadata so only the WindowManager needs to set this on root Surfaces.
- *
- * @param windowType A window-type
- * @param ownerUid UID of the window owner.
+ * @param key metadata key
+ * @param data associated data
* @hide
*/
- public Builder setMetadata(int windowType, int ownerUid) {
- if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
- throw new UnsupportedOperationException(
- "It only makes sense to set Surface metadata from the WindowManager");
+ public Builder setMetadata(int key, int data) {
+ if (mMetadata == null) {
+ mMetadata = new SparseIntArray();
}
- mWindowType = windowType;
- mOwnerUid = ownerUid;
+ mMetadata.put(key, data);
return this;
}
@@ -682,13 +694,12 @@
* @param h The surface initial height.
* @param flags The surface creation flags. Should always include {@link #HIDDEN}
* in the creation flags.
- * @param windowType The type of the window as specified in WindowManager.java.
- * @param ownerUid A unique per-app ID.
+ * @param metadata Initial metadata.
*
* @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
*/
private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
- SurfaceControl parent, int windowType, int ownerUid)
+ SurfaceControl parent, SparseIntArray metadata)
throws OutOfResourcesException, IllegalArgumentException {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
@@ -706,8 +717,21 @@
mName = name;
mWidth = w;
mHeight = h;
- mNativeObject = nativeCreate(session, name, w, h, format, flags,
- parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
+ Parcel metaParcel = Parcel.obtain();
+ try {
+ if (metadata != null && metadata.size() > 0) {
+ metaParcel.writeInt(metadata.size());
+ for (int i = 0; i < metadata.size(); ++i) {
+ metaParcel.writeInt(metadata.keyAt(i));
+ metaParcel.writeByteArray(
+ ByteBuffer.allocate(4).putInt(metadata.valueAt(i)).array());
+ }
+ }
+ mNativeObject = nativeCreate(session, name, w, h, format, flags,
+ parent != null ? parent.mNativeObject : 0, metaParcel);
+ } finally {
+ metaParcel.recycle();
+ }
if (mNativeObject == 0) {
throw new OutOfResourcesException(
"Couldn't allocate SurfaceControl native object");
@@ -2326,6 +2350,30 @@
}
/**
+ * Sets an arbitrary piece of metadata on the surface. This is a helper for int data.
+ * @hide
+ */
+ public Transaction setMetadata(int key, int data) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeInt(data);
+ try {
+ setMetadata(key, parcel);
+ } finally {
+ parcel.recycle();
+ }
+ return this;
+ }
+
+ /**
+ * Sets an arbitrary piece of metadata on the surface.
+ * @hide
+ */
+ public Transaction setMetadata(int key, Parcel data) {
+ nativeSetMetadata(mNativeObject, key, data);
+ return this;
+ }
+
+ /**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
*
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 69877c7..f1b259e 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -124,7 +124,7 @@
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
- jint windowType, jint ownerUid) {
+ jobject metadataParcel) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client;
if (sessionObj != NULL) {
@@ -134,8 +134,18 @@
}
SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
sp<SurfaceControl> surface;
+ LayerMetadata metadata;
+ Parcel* parcel = parcelForJavaObject(env, metadataParcel);
+ if (parcel && !parcel->objectsCount()) {
+ status_t err = metadata.readFromParcel(parcel);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Metadata parcel has wrong format");
+ }
+ }
+
status_t err = client->createSurfaceChecked(
- String8(name.c_str()), w, h, format, &surface, flags, parent, windowType, ownerUid);
+ String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));
if (err == NAME_NOT_FOUND) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return 0;
@@ -377,6 +387,28 @@
transaction->transferTouchFocus(fromToken, toToken);
}
+static void nativeSetMetadata(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jint id, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ if (!parcel) {
+ jniThrowNullPointerException(env, "attribute data");
+ return;
+ }
+ if (parcel->objectsCount()) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Tried to marshall a Parcel that contained Binder objects.");
+ return;
+ }
+
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ std::vector<uint8_t> byteData(parcel->dataSize());
+ memcpy(byteData.data(), parcel->data(), parcel->dataSize());
+
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ transaction->setMetadata(ctrl, id, std::move(byteData));
+}
+
static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jfloatArray fColor) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -981,7 +1013,7 @@
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
- {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJII)J",
+ {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJLandroid/os/Parcel;)J",
(void*)nativeCreate },
{"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
(void*)nativeReadFromParcel },
@@ -1099,6 +1131,8 @@
(void*)nativeSetInputWindowInfo },
{"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V",
(void*)nativeTransferTouchFocus },
+ {"nativeSetMetadata", "(JILandroid/os/Parcel;)V",
+ (void*)nativeSetMetadata },
{"nativeGetDisplayedContentSamplingAttributes",
"(Landroid/os/IBinder;)Landroid/hardware/display/DisplayedContentSamplingAttributes;",
(void*)nativeGetDisplayedContentSamplingAttributes },
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 4e48663..4b37f13 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -423,13 +423,13 @@
}
void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const {
- const int dev_null_fd = open("/dev/null", O_RDWR);
+ const int dev_null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
if (dev_null_fd < 0) {
fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
}
- if (dup2(dev_null_fd, fd) == -1) {
- fail_fn(android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
+ if (dup3(dev_null_fd, fd, O_CLOEXEC) == -1) {
+ fail_fn(android::base::StringPrintf("Failed dup3 on socket descriptor %d: %s",
fd,
strerror(errno)));
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4a54bd7..893a607 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -43,7 +43,7 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ENABLE_ROLLBACK" />
- <protected-broadcast android:name="android.intent.action.PACKAGE_ROLLBACK_EXECUTED" />
+ <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 4755d45..c9e4694 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1821,6 +1821,8 @@
* @param cct The correlated color temperature, in Kelvin
* @return Corresponding XYZ values
* @throws IllegalArgumentException If cct is invalid
+ *
+ * @hide
*/
@NonNull
@Size(3)
@@ -1851,6 +1853,8 @@
* @param srcWhitePoint The white point to adapt from
* @param dstWhitePoint The white point to adapt to
* @return A 3x3 matrix as a non-null array of 9 floats
+ *
+ * @hide
*/
@NonNull
@Size(9)
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a45aa90..417a427 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -405,6 +405,11 @@
nativeFormat, consumerUsage);
return;
}
+
+ if (consumerUsage & GRALLOC_USAGE_PROTECTED) {
+ gbConsumer->setConsumerIsProtected(true);
+ }
+
ctx->setBufferConsumer(bufferConsumer);
bufferConsumer->setName(consumerName);
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 5fae9d5..3156732 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -47,32 +47,13 @@
static bool getWideColorSupport(const sp<SurfaceControl>& surfaceControl) {
sp<SurfaceComposerClient> client = surfaceControl->getClient();
sp<IBinder> display(client->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-
- Vector<ui::ColorMode> colorModes;
- status_t err = client->getDisplayColorModes(display, &colorModes);
+ bool isWideColorDisplay = false;
+ status_t err = client->isWideColorDisplay(display, &isWideColorDisplay);
if (err) {
ALOGE("unable to get wide color support");
return false;
}
-
- bool wideColorBoardConfig =
- getBool<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
-
- for (android::ui::ColorMode colorMode : colorModes) {
- switch (colorMode) {
- case ui::ColorMode::DISPLAY_P3:
- case ui::ColorMode::ADOBE_RGB:
- case ui::ColorMode::DCI_P3:
- if (wideColorBoardConfig) {
- return true;
- }
- break;
- default:
- break;
- }
- }
- return false;
+ return isWideColorDisplay;
}
static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) {
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index d09823e..a5a515f 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -34,11 +34,11 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.Preconditions;
@@ -48,6 +48,9 @@
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
/**
* Find the best Service, and bind to it.
@@ -61,16 +64,20 @@
public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
- /**
- * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
- */
+
+ /** Function to run on binder interface. */
public interface BinderRunner {
- /**
- * Runs on the retrieved binder.
- *
- * @param binder the binder retrieved from the {@link ServiceWatcher}.
- */
- void run(IBinder binder);
+ /** Called to run client code with the binder. */
+ void run(IBinder binder) throws RemoteException;
+ }
+
+ /**
+ * Function to run on binder interface.
+ * @param <T> Type to return.
+ */
+ public interface BlockingBinderRunner<T> {
+ /** Called to run client code with the binder. */
+ T run(IBinder binder) throws RemoteException;
}
public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
@@ -120,18 +127,14 @@
private final Handler mHandler;
- // this lock is held to ensure the service binder is not exposed (via runOnBinder) until after
- // the new service initialization work has completed
- private final Object mBindLock = new Object();
-
// read/write from handler thread
+ private IBinder mBestService;
private int mCurrentUserId;
// read from any thread, write from handler thread
private volatile ComponentName mBestComponent;
private volatile int mBestVersion;
private volatile int mBestUserId;
- private volatile IBinder mBestService;
public ServiceWatcher(Context context, String logTag, String action,
int overlaySwitchResId, int defaultServicePackageNameResId,
@@ -163,17 +166,9 @@
mBestService = null;
}
- // called on handler thread
- @GuardedBy("mBindLock")
- protected void onBind() {
- Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- }
+ protected void onBind() {}
- // called on handler thread
- @GuardedBy("mBindLock")
- protected void onUnbind() {
- Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- }
+ protected void onUnbind() {}
/**
* Start this watcher, including binding to the current best match and
@@ -248,25 +243,6 @@
return bestComponent == null ? null : bestComponent.getPackageName();
}
- /**
- * Runs the given BinderRunner if currently connected. All invocations to runOnBinder are run
- * serially.
- */
- public final void runOnBinder(BinderRunner runner) {
- synchronized (mBindLock) {
- IBinder service = mBestService;
- if (service != null) {
- try {
- runner.run(service);
- } catch (Exception e) {
- // remote exceptions cannot be allowed to crash system server
- Log.e(TAG, "exception while while running " + runner + " on " + service
- + " from " + this, e);
- }
- }
- }
- }
-
private boolean isServiceMissing() {
return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction),
PackageManager.MATCH_DIRECT_BOOT_AWARE
@@ -380,28 +356,66 @@
mBestUserId = UserHandle.USER_NULL;
}
+ /**
+ * Runs the given function asynchronously if currently connected. Suppresses any RemoteException
+ * thrown during execution.
+ */
+ public final void runOnBinder(BinderRunner runner) {
+ runOnHandler(() -> {
+ if (mBestService == null) {
+ return;
+ }
+
+ try {
+ runner.run(mBestService);
+ } catch (RuntimeException e) {
+ // the code being run is privileged, but may be outside the system server, and thus
+ // we cannot allow runtime exceptions to crash the system server
+ Log.e(TAG, "exception while while running " + runner + " on " + mBestService
+ + " from " + this, e);
+ } catch (RemoteException e) {
+ // do nothing
+ }
+ });
+ }
+
+ /**
+ * Runs the given function synchronously if currently connected, and returns the default value
+ * if not currently connected or if any exception is thrown.
+ */
+ public final <T> T runOnBinderBlocking(BlockingBinderRunner<T> runner, T defaultValue) {
+ try {
+ return runOnHandlerBlocking(() -> {
+ if (mBestService == null) {
+ return defaultValue;
+ }
+
+ try {
+ return runner.run(mBestService);
+ } catch (RemoteException e) {
+ return defaultValue;
+ }
+ });
+ } catch (InterruptedException e) {
+ return defaultValue;
+ }
+ }
+
@Override
public final void onServiceConnected(ComponentName component, IBinder binder) {
- mHandler.post(() -> {
+ runOnHandler(() -> {
if (D) Log.d(mTag, component + " connected");
-
- // hold the lock so that mBestService cannot be used by runOnBinder until complete
- synchronized (mBindLock) {
- mBestService = binder;
- onBind();
- }
+ mBestService = binder;
+ onBind();
});
}
@Override
public final void onServiceDisconnected(ComponentName component) {
- mHandler.post(() -> {
+ runOnHandler(() -> {
if (D) Log.d(mTag, component + " disconnected");
-
mBestService = null;
- synchronized (mBindLock) {
- onUnbind();
- }
+ onUnbind();
});
}
@@ -410,4 +424,32 @@
ComponentName bestComponent = mBestComponent;
return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion;
}
+
+ private void runOnHandler(Runnable r) {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ r.run();
+ } else {
+ mHandler.post(r);
+ }
+ }
+
+ private <T> T runOnHandlerBlocking(Callable<T> c) throws InterruptedException {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ try {
+ return c.call();
+ } catch (Exception e) {
+ // Function cannot throw exception, this should never happen
+ throw new IllegalStateException(e);
+ }
+ } else {
+ FutureTask<T> task = new FutureTask<>(c);
+ mHandler.post(task);
+ try {
+ return task.get();
+ } catch (ExecutionException e) {
+ // Function cannot throw exception, this should never happen
+ throw new IllegalStateException(e);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 41fedc5..15d66e6 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -29,10 +29,12 @@
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.IActivityTaskManager;
+import android.app.KeyguardManager;
import android.app.TaskStackListener;
import android.app.UserSwitchObserver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -377,6 +379,13 @@
new BiometricTaskStackListener();
private final Random mRandom = new Random();
+ // TODO(b/123378871): Remove when moved.
+ // When BiometricPrompt#setEnableFallback is set to true, we need to store the client (app)
+ // receiver. BiometricService internally launches CDCA which invokes BiometricService to
+ // start authentication (normal path). When auth is success/rejected, CDCA will use an aidl
+ // method to poke BiometricService - the result will then be forwarded to this receiver.
+ private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
+
// The current authentication session, null if idle/done. We need to track both the current
// and pending sessions since errors may be sent to either.
private AuthSession mCurrentAuthSession;
@@ -705,6 +714,22 @@
}
}
+ // Launch CDC instead if necessary. CDC will return results through an AIDL call, since
+ // we can't get activity results. Store the receiver somewhere so we can forward the
+ // result back to the client.
+ // TODO(b/123378871): Remove when moved.
+ if (bundle.getBoolean(BiometricPrompt.KEY_ENABLE_FALLBACK)) {
+ mConfirmDeviceCredentialReceiver = receiver;
+ final KeyguardManager kgm = getContext().getSystemService(KeyguardManager.class);
+ // Use this so we don't need to duplicate logic..
+ final Intent intent = kgm.createConfirmDeviceCredentialIntent(null /* title */,
+ null /* description */);
+ // Then give it the bundle to do magic behavior..
+ intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle);
+ getContext().startActivityAsUser(intent, UserHandle.CURRENT);
+ return;
+ }
+
mHandler.post(() -> {
final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
final int modality = result.first;
@@ -745,6 +770,36 @@
});
}
+ @Override // Binder call
+ public void onConfirmDeviceCredentialSuccess() {
+ checkInternalPermission();
+ if (mConfirmDeviceCredentialReceiver == null) {
+ Slog.w(TAG, "onCDCASuccess null!");
+ return;
+ }
+ try {
+ mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ mConfirmDeviceCredentialReceiver = null;
+ }
+
+ @Override // Binder call
+ public void onConfirmDeviceCredentialError(int error, String message) {
+ checkInternalPermission();
+ if (mConfirmDeviceCredentialReceiver == null) {
+ Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+ return;
+ }
+ try {
+ mConfirmDeviceCredentialReceiver.onError(error, message);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ mConfirmDeviceCredentialReceiver = null;
+ }
+
/**
* authenticate() (above) which is called from BiometricPrompt determines which
* modality/modalities to start authenticating with. authenticateInternal() should only be
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index cb3f91b..b89768a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -36,6 +36,7 @@
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.ColorSpace;
import android.graphics.Point;
import android.hardware.SensorManager;
import android.hardware.display.AmbientBrightnessDayStats;
@@ -93,9 +94,9 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
+import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.wm.SurfaceAnimationThread;
import com.android.server.wm.WindowManagerInternal;
-import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -294,6 +295,7 @@
// is rejected by the system.
private final Curve mMinimumBrightnessCurve;
private final Spline mMinimumBrightnessSpline;
+ private final ColorSpace mWideColorSpace;
public DisplayManagerService(Context context) {
this(context, new Injector());
@@ -322,6 +324,8 @@
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
mCurrentUserId = UserHandle.USER_SYSTEM;
+ ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
+ mWideColorSpace = colorSpaces[1];
}
public void setupSchedulerPolicies() {
@@ -1073,6 +1077,10 @@
return mMinimumBrightnessCurve;
}
+ int getPreferredWideGamutColorSpaceIdInternal() {
+ return mWideColorSpace.getId();
+ }
+
private void setBrightnessConfigurationForUserInternal(
@Nullable BrightnessConfiguration c, @UserIdInt int userId,
@Nullable String packageName) {
@@ -2128,6 +2136,16 @@
}
}
+ @Override // Binder call
+ public int getPreferredWideGamutColorSpaceId() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getPreferredWideGamutColorSpaceIdInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
void setBrightness(int brightness) {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, brightness, UserHandle.USER_CURRENT);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index cfc85da..326984c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -34,6 +34,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
@@ -756,6 +757,14 @@
*/
private final ArrayMap<String, String> mCopyOnWriteDataStore = new ArrayMap<>();
+ private static final ArraySet<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+ static {
+ Settings.Secure.getCloneToManagedProfileSettings(CLONE_TO_MANAGED_PROFILE);
+ }
+
+ private static final UserManagerInternal sUserManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+
private boolean mCopyOnWrite = false;
@NonNull
private String mEnabledInputMethodsStrCache = "";
@@ -833,7 +842,9 @@
if (mCopyOnWrite) {
mCopyOnWriteDataStore.put(key, str);
} else {
- Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+ final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
+ ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
+ Settings.Secure.putStringForUser(mResolver, key, str, userId);
}
}
@@ -852,7 +863,9 @@
if (mCopyOnWrite) {
mCopyOnWriteDataStore.put(key, String.valueOf(value));
} else {
- Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+ final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
+ ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
+ Settings.Secure.putIntForUser(mResolver, key, value, userId);
}
}
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index f1de371..e6f0ed9 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -20,8 +20,6 @@
import android.location.Address;
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
-import android.os.RemoteException;
-import android.util.Log;
import com.android.internal.os.BackgroundThread;
import com.android.server.ServiceWatcher;
@@ -68,35 +66,22 @@
public String getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- final String[] result = new String[]{"Service not Available"};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- try {
- result[0] = provider.getFromLocation(
- latitude, longitude, maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return result[0];
+ return provider.getFromLocation(latitude, longitude, maxResults, params, addrs);
+ }, "Service not Available");
}
public String getFromLocationName(String locationName,
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- final String[] result = new String[]{"Service not Available"};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- try {
- result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return result[0];
+ return provider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ }, "Service not Available");
}
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index a6da8c5..6b5b1be 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -127,20 +127,16 @@
return mServiceWatcher.start();
}
- private void initializeService(IBinder binder) {
+ private void initializeService(IBinder binder) throws RemoteException {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
- try {
- service.setLocationProviderManager(mManager);
+ service.setLocationProviderManager(mManager);
- synchronized (mRequestLock) {
- if (mRequest != null) {
- service.setRequest(mRequest, mWorkSource);
- }
+ synchronized (mRequestLock) {
+ if (mRequest != null) {
+ service.setRequest(mRequest, mWorkSource);
}
- } catch (RemoteException e) {
- Log.w(TAG, e);
}
}
@@ -157,63 +153,44 @@
}
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.setRequest(request, source);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
+ service.setRequest(request, source);
});
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(" service=" + mServiceWatcher);
- mServiceWatcher.runOnBinder(binder -> {
+ mServiceWatcher.runOnBinderBlocking(binder -> {
try {
TransferPipe.dumpAsync(binder, fd, args);
} catch (IOException | RemoteException e) {
- pw.println(" failed to dump location provider: " + e);
+ pw.println(" failed to dump location provider");
}
- });
+ return null;
+ }, null);
}
@Override
public int getStatus(Bundle extras) {
- int[] status = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- status[0] = service.getStatus(extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return status[0];
+ return service.getStatus(extras);
+ }, LocationProvider.TEMPORARILY_UNAVAILABLE);
}
@Override
public long getStatusUpdateTime() {
- long[] updateTime = new long[] {0L};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- updateTime[0] = service.getStatusUpdateTime();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return updateTime[0];
+ return service.getStatusUpdateTime();
+ }, 0L);
}
@Override
public void sendExtraCommand(String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.sendExtraCommand(command, extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
+ service.sendExtraCommand(command, extras);
});
}
}
diff --git a/services/core/java/com/android/server/location/OWNERS b/services/core/java/com/android/server/location/OWNERS
index 92b4d5f..c2c95e6 100644
--- a/services/core/java/com/android/server/location/OWNERS
+++ b/services/core/java/com/android/server/location/OWNERS
@@ -1,6 +1,8 @@
+aadmal@google.com
arthuri@google.com
bduddie@google.com
gomo@google.com
sooniln@google.com
weiwa@google.com
wyattriley@google.com
+yuhany@google.com
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a164686..de3f50a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1087,7 +1087,8 @@
|| (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
|| action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
- || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
+ || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
+ || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_ALL);
String pkgList[] = null;
@@ -1108,6 +1109,23 @@
uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
cancelNotifications = false;
unhideNotifications = true;
+ } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
+ final int distractionRestrictions =
+ intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
+ PackageManager.RESTRICTION_NONE);
+ if ((distractionRestrictions
+ & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+ cancelNotifications = false;
+ hideNotifications = true;
+ } else {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+ cancelNotifications = false;
+ unhideNotifications = true;
+ }
+
} else if (queryRestart) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
@@ -1651,6 +1669,7 @@
IntentFilter suspendedPkgFilter = new IntentFilter();
suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
suspendedPkgFilter, null, null);
@@ -7743,6 +7762,20 @@
mPackageIntentReceiver.onReceive(getContext(), intent);
}
+ @VisibleForTesting
+ protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
+ // only use for testing: mimic receive broadcast that package is (un)distracting
+ // but does not actually register that info with packagemanager
+ final Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
+
+ final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
+ intent.putExtras(extras);
+
+ mPackageIntentReceiver.onReceive(getContext(), intent);
+ }
+
/**
* Wrapper for a StatusBarNotification object that allows transfer across a oneway
* binder without sending large amounts of data over a oneway transaction.
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 3d88f20..2aaa1ed 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -176,6 +176,14 @@
// only use for testing
mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
}
+ case "distract_package": {
+ // only use for testing
+ // Flag values are in
+ // {@link android.content.pm.PackageManager.DistractionRestriction}.
+ mDirectService.simulatePackageDistractionBroadcast(
+ Integer.parseInt(getNextArgRequired()),
+ getNextArgRequired().split(","));
+ }
break;
case "post":
case "notify":
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 8b4c410..6487bd7 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -28,7 +28,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
-import android.content.pm.StringParceledListSlice;
import android.content.pm.VersionedPackage;
import android.content.rollback.IRollbackManager;
import android.content.rollback.PackageRollbackInfo;
@@ -56,12 +55,10 @@
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
-import java.util.Set;
/**
* Implementation of service that manages APK level rollbacks.
@@ -200,48 +197,20 @@
}
@Override
- public RollbackInfo getAvailableRollback(String packageName) {
+ public ParceledListSlice getAvailableRollbacks() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_ROLLBACKS,
- "getAvailableRollback");
+ "getAvailableRollbacks");
- RollbackData data = getRollbackForPackage(packageName);
- if (data == null) {
- return null;
- }
-
- // Note: The rollback for the package ought to be for the currently
- // installed version, otherwise the rollback data is out of date. In
- // that rare case, we'll check when we execute the rollback whether
- // it's out of date or not, so no need to check package versions here.
-
- for (PackageRollbackInfo info : data.packages) {
- if (info.getPackageName().equals(packageName)) {
- // TODO: Once the RollbackInfo API supports info about
- // dependant packages, add that info here.
- return new RollbackInfo(data.rollbackId, info);
- }
- }
- return null;
- }
-
- @Override
- public StringParceledListSlice getPackagesWithAvailableRollbacks() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "getPackagesWithAvailableRollbacks");
-
- final Set<String> packageNames = new HashSet<>();
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
+ List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
RollbackData data = mAvailableRollbacks.get(i);
- for (PackageRollbackInfo info : data.packages) {
- packageNames.add(info.getPackageName());
- }
+ rollbacks.add(new RollbackInfo(data.rollbackId, data.packages));
}
+ return new ParceledListSlice<>(rollbacks);
}
- return new StringParceledListSlice(new ArrayList<>(packageNames));
}
@Override
@@ -279,18 +248,11 @@
*/
private void executeRollbackInternal(RollbackInfo rollback,
String callerPackageName, IntentSender statusReceiver) {
- String targetPackageName = rollback.targetPackage.getPackageName();
- Log.i(TAG, "Initiating rollback of " + targetPackageName);
+ Log.i(TAG, "Initiating rollback");
- // Get the latest RollbackData for the target package.
- final RollbackData data = getRollbackForPackage(targetPackageName);
+ RollbackData data = getRollbackForId(rollback.getRollbackId());
if (data == null) {
- sendFailure(statusReceiver, "No rollback available for package.");
- return;
- }
-
- if (data.rollbackId != rollback.getRollbackId()) {
- sendFailure(statusReceiver, "Rollback for package is out of date.");
+ sendFailure(statusReceiver, "Rollback unavailable");
return;
}
@@ -335,14 +297,8 @@
PackageManager pm = context.getPackageManager();
try {
PackageInstaller packageInstaller = pm.getPackageInstaller();
- String installerPackageName = pm.getInstallerPackageName(targetPackageName);
- if (installerPackageName == null) {
- sendFailure(statusReceiver, "Cannot find installer package");
- return;
- }
PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- parentParams.setInstallerPackageName(installerPackageName);
parentParams.setAllowDowngrade(true);
parentParams.setMultiPackage();
int parentSessionId = packageInstaller.createSession(parentParams);
@@ -351,6 +307,11 @@
for (PackageRollbackInfo info : data.packages) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ String installerPackageName = pm.getInstallerPackageName(info.getPackageName());
+ if (installerPackageName == null) {
+ sendFailure(statusReceiver, "Cannot find installer package");
+ return;
+ }
params.setInstallerPackageName(installerPackageName);
params.setAllowDowngrade(true);
int sessionId = packageInstaller.createSession(params);
@@ -392,7 +353,7 @@
addRecentlyExecutedRollback(rollback);
sendSuccess(statusReceiver);
- Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+ Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
// TODO: This call emits the warning "Calling a method in the
// system process without a qualified user". Fix that.
@@ -406,7 +367,7 @@
data.inProgress = true;
parentSession.commit(receiver.getIntentSender());
} catch (IOException e) {
- Log.e(TAG, "Unable to roll back " + targetPackageName, e);
+ Log.e(TAG, "Rollback failed", e);
sendFailure(statusReceiver, "IOException: " + e.toString());
return;
}
@@ -537,9 +498,12 @@
boolean changed = false;
while (iter.hasNext()) {
RollbackInfo rollback = iter.next();
- if (packageName.equals(rollback.targetPackage.getPackageName())) {
- iter.remove();
- changed = true;
+ for (PackageRollbackInfo info : rollback.getPackages()) {
+ if (packageName.equals(info.getPackageName())) {
+ iter.remove();
+ changed = true;
+ break;
+ }
}
}
@@ -935,6 +899,25 @@
return null;
}
+ /*
+ * Returns the RollbackData, if any, for an available rollback with the
+ * given rollbackId.
+ */
+ private RollbackData getRollbackForId(int rollbackId) {
+ synchronized (mLock) {
+ // TODO: Have ensureRollbackDataLoadedLocked return the list of
+ // available rollbacks, to hopefully avoid forgetting to call it?
+ ensureRollbackDataLoadedLocked();
+ for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+ RollbackData data = mAvailableRollbacks.get(i);
+ if (data.rollbackId == rollbackId) {
+ return data;
+ }
+ }
+ }
+ return null;
+ }
+
@GuardedBy("mLock")
private int allocateRollbackIdLocked() throws IOException {
int n = 0;
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 1f2f1cc..3954a11 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
+import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Handler;
@@ -51,11 +52,14 @@
@Override
public boolean onHealthCheckFailed(String packageName) {
RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
- RollbackInfo rollback = rollbackManager.getAvailableRollback(packageName);
- if (rollback != null) {
- // TODO(zezeozue): Only rollback if rollback version == failed package version
- mHandler.post(() -> executeRollback(rollbackManager, rollback));
- return true;
+ for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
+ for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
+ if (packageName.equals(packageRollback.getPackageName())) {
+ // TODO(zezeozue): Only rollback if rollback version == failed package version
+ mHandler.post(() -> executeRollback(rollbackManager, rollback));
+ return true;
+ }
+ }
}
// Don't handle the notification, no rollbacks available
return false;
@@ -84,7 +88,7 @@
}
});
});
- manager.executeRollback(rollback, rollbackReceiver.getIntentSender());
+ manager.commitRollback(rollback, rollbackReceiver.getIntentSender());
}
@Override
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 7738be9..3b24b3e 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -114,13 +114,9 @@
for (int i = 0; i < array.length(); ++i) {
JSONObject element = array.getJSONObject(i);
int rollbackId = element.getInt("rollbackId");
- String packageName = element.getString("packageName");
- long higherVersionCode = element.getLong("higherVersionCode");
- long lowerVersionCode = element.getLong("lowerVersionCode");
- PackageRollbackInfo target = new PackageRollbackInfo(
- new VersionedPackage(packageName, higherVersionCode),
- new VersionedPackage(packageName, lowerVersionCode));
- RollbackInfo rollback = new RollbackInfo(rollbackId, target);
+ List<PackageRollbackInfo> packages = packageRollbackInfosFromJson(
+ element.getJSONArray("packages"));
+ RollbackInfo rollback = new RollbackInfo(rollbackId, packages);
recentlyExecutedRollbacks.add(rollback);
}
} catch (IOException | JSONException e) {
@@ -155,18 +151,8 @@
void saveAvailableRollback(RollbackData data) throws IOException {
try {
JSONObject dataJson = new JSONObject();
- JSONArray packagesJson = new JSONArray();
- for (PackageRollbackInfo info : data.packages) {
- JSONObject infoJson = new JSONObject();
- infoJson.put("packageName", info.getPackageName());
- infoJson.put("higherVersionCode",
- info.getVersionRolledBackFrom().getLongVersionCode());
- infoJson.put("lowerVersionCode",
- info.getVersionRolledBackTo().getVersionCode());
- packagesJson.put(infoJson);
- }
dataJson.put("rollbackId", data.rollbackId);
- dataJson.put("packages", packagesJson);
+ dataJson.put("packages", toJson(data.packages));
dataJson.put("timestamp", data.timestamp.toString());
PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
@@ -200,11 +186,7 @@
RollbackInfo rollback = recentlyExecutedRollbacks.get(i);
JSONObject element = new JSONObject();
element.put("rollbackId", rollback.getRollbackId());
- element.put("packageName", rollback.targetPackage.getPackageName());
- element.put("higherVersionCode",
- rollback.targetPackage.getVersionRolledBackFrom().getLongVersionCode());
- element.put("lowerVersionCode",
- rollback.targetPackage.getVersionRolledBackTo().getLongVersionCode());
+ element.put("packages", toJson(rollback.getPackages()));
array.put(element);
}
@@ -229,18 +211,7 @@
int rollbackId = dataJson.getInt("rollbackId");
RollbackData data = new RollbackData(rollbackId, backupDir);
-
- JSONArray packagesJson = dataJson.getJSONArray("packages");
- for (int i = 0; i < packagesJson.length(); ++i) {
- JSONObject infoJson = packagesJson.getJSONObject(i);
- String packageName = infoJson.getString("packageName");
- long higherVersionCode = infoJson.getLong("higherVersionCode");
- long lowerVersionCode = infoJson.getLong("lowerVersionCode");
- data.packages.add(new PackageRollbackInfo(
- new VersionedPackage(packageName, higherVersionCode),
- new VersionedPackage(packageName, lowerVersionCode)));
- }
-
+ data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages")));
data.timestamp = Instant.parse(dataJson.getString("timestamp"));
return data;
} catch (JSONException | DateTimeParseException e) {
@@ -248,6 +219,40 @@
}
}
+ private JSONObject toJson(PackageRollbackInfo info) throws JSONException {
+ JSONObject json = new JSONObject();
+ json.put("packageName", info.getPackageName());
+ json.put("higherVersionCode", info.getVersionRolledBackFrom().getLongVersionCode());
+ json.put("lowerVersionCode", info.getVersionRolledBackTo().getLongVersionCode());
+ return json;
+ }
+
+ private PackageRollbackInfo packageRollbackInfoFromJson(JSONObject json) throws JSONException {
+ String packageName = json.getString("packageName");
+ long higherVersionCode = json.getLong("higherVersionCode");
+ long lowerVersionCode = json.getLong("lowerVersionCode");
+ return new PackageRollbackInfo(
+ new VersionedPackage(packageName, higherVersionCode),
+ new VersionedPackage(packageName, lowerVersionCode));
+ }
+
+ private JSONArray toJson(List<PackageRollbackInfo> infos) throws JSONException {
+ JSONArray json = new JSONArray();
+ for (PackageRollbackInfo info : infos) {
+ json.put(toJson(info));
+ }
+ return json;
+ }
+
+ private List<PackageRollbackInfo> packageRollbackInfosFromJson(JSONArray json)
+ throws JSONException {
+ List<PackageRollbackInfo> infos = new ArrayList<>();
+ for (int i = 0; i < json.length(); ++i) {
+ infos.add(packageRollbackInfoFromJson(json.getJSONObject(i)));
+ }
+ return infos;
+ }
+
/**
* Deletes a file completely.
* If the file is a directory, its contents are deleted as well.
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 29645f6..ed029cd 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import static android.view.SurfaceControl.METADATA_OWNER_UID;
+import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
+
import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT;
import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR;
import static com.android.server.wm.AppWindowThumbnailProto.WIDTH;
@@ -82,7 +85,8 @@
.setName("thumbnail anim: " + appToken.toString())
.setBufferSize(mWidth, mHeight)
.setFormat(PixelFormat.TRANSLUCENT)
- .setMetadata(appToken.windowType,
+ .setMetadata(METADATA_WINDOW_TYPE, appToken.windowType)
+ .setMetadata(METADATA_OWNER_UID,
window != null ? window.mOwnerUid : Binder.getCallingUid())
.build();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a7dd55b..476bd6e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,6 +22,7 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.EMPTY;
+import static android.view.SurfaceControl.METADATA_TASK_ID;
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
@@ -643,6 +644,11 @@
return getAppAnimationLayer(ANIMATION_LAYER_HOME);
}
+ @Override
+ SurfaceControl.Builder makeSurface() {
+ return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId);
+ }
+
boolean isTaskAnimating() {
final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController();
if (recentsAnim != null) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index c2a8e7e..dea3597 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -18,6 +18,8 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
+import static android.view.SurfaceControl.METADATA_OWNER_UID;
+import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -35,7 +37,6 @@
import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowContentFrameStats;
@@ -103,7 +104,8 @@
.setBufferSize(w, h)
.setFormat(format)
.setFlags(flags)
- .setMetadata(windowType, ownerUid);
+ .setMetadata(METADATA_WINDOW_TYPE, windowType)
+ .setMetadata(METADATA_OWNER_UID, ownerUid);
mSurfaceControl = b.build();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 6222923..9c6ab0a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3410,6 +3410,77 @@
}
@Test
+ public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() {
+ // Post 2 notifications from 2 packages
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ // on broadcast, hide one of the packages
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"});
+ ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
+ assertEquals(1, captorHide.getValue().size());
+ assertEquals("a", captorHide.getValue().get(0).sbn.getPackageName());
+
+ // on broadcast, unhide the package
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"});
+ ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
+ assertEquals(1, captorUnhide.getValue().size());
+ assertEquals("a", captorUnhide.getValue().get(0).sbn.getPackageName());
+ }
+
+ @Test
+ public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() {
+ // Post 2 notifications from 2 packages
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ // on broadcast, hide one of the packages
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"});
+ ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(2)).notifyHiddenLocked(captorHide.capture());
+ assertEquals(2, captorHide.getValue().size());
+ assertEquals("a", captorHide.getValue().get(0).sbn.getPackageName());
+ assertEquals("b", captorHide.getValue().get(1).sbn.getPackageName());
+
+ // on broadcast, unhide the package
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"});
+ ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(2)).notifyUnhiddenLocked(captorUnhide.capture());
+ assertEquals(2, captorUnhide.getValue().size());
+ assertEquals("a", captorUnhide.getValue().get(0).sbn.getPackageName());
+ assertEquals("b", captorUnhide.getValue().get(1).sbn.getPackageName());
+ }
+
+ @Test
+ public void testNoNotificationsHiddenOnDistractingPackageBroadcast() {
+ // post notification from this package
+ final NotificationRecord notif1 = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ mService.addNotification(notif1);
+
+ // on broadcast, nothing is hidden since no notifications are of package "test_package"
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"});
+ ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
+ assertEquals(0, captor.getValue().size());
+ }
+
+ @Test
public void testCanUseManagedServicesLowRamNoWatchNullPkg() {
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
when(mActivityManager.isLowRamDevice()).thenReturn(true);
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index d777bf1..aaca18a 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -16,6 +16,8 @@
package android.telephony;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
@@ -2145,6 +2147,79 @@
}
/**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * The prefixes is a list of prefix {@code String} separated by this delimiter.
+ * @hide
+ */
+ public static final String REGEX_PREFIX_DELIMITER = ",";
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * The success status to be added into the intent to be sent to the calling package.
+ * @hide
+ */
+ public static final int RESULT_STATUS_SUCCESS = 0;
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * The timeout status to be added into the intent to be sent to the calling package.
+ * @hide
+ */
+ public static final int RESULT_STATUS_TIMEOUT = 1;
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * Intent extra key of the retrieved SMS message as a {@code String}.
+ * @hide
+ */
+ public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE";
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * Intent extra key of SMS retriever status, which indicates whether the request for the
+ * coming SMS message is SUCCESS or TIMEOUT
+ * @hide
+ */
+ public static final String EXTRA_STATUS = "android.telephony.extra.STATUS";
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int}
+ * @hide
+ */
+ public static final String EXTRA_SIM_SUBSCRIPTION_ID =
+ "android.telephony.extra.SIM_SUBSCRIPTION_ID";
+
+ /**
+ * Create a single use app specific incoming SMS request for the calling package.
+ *
+ * This method returns a token that if included in a subsequent incoming SMS message, and the
+ * SMS message has a prefix from the given prefixes list, the provided {@code intent} will be
+ * sent with the SMS data to the calling package.
+ *
+ * The token is only good for one use within a reasonable amount of time. After an SMS has been
+ * received containing the token all subsequent SMS messages with the token will be routed as
+ * normal.
+ *
+ * An app can only have one request at a time, if the app already has a request pending it will
+ * be replaced with a new request.
+ *
+ * @param prefixes this is a list of prefixes string separated by REGEX_PREFIX_DELIMITER. The
+ * matching SMS message should have at least one of the prefixes in the beginning of the
+ * message.
+ * @param intent this intent is sent when the matching SMS message is received.
+ * @return Token to include in an SMS message.
+ */
+ @Nullable
+ public String createAppSpecificSmsTokenWithPackageInfo(
+ @Nullable String prefixes, @NonNull PendingIntent intent) {
+ try {
+ ISms iccSms = getISmsServiceOrThrow();
+ return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
+ ActivityThread.currentPackageName(), prefixes, intent);
+
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
+ /**
* Filters a bundle to only contain MMS config variables.
*
* This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index a4eb424..58ebb15 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -560,4 +560,19 @@
* @param intent PendingIntent to be sent when an SMS is received containing the token.
*/
String createAppSpecificSmsToken(int subId, String callingPkg, in PendingIntent intent);
+
+ /**
+ * Create an app-only incoming SMS request for the calling package.
+ *
+ * If an incoming text contains the token returned by this method the provided
+ * <code>PendingIntent</code> will be sent containing the SMS data.
+ *
+ * @param subId the SIM id.
+ * @param callingPkg the package name of the calling app.
+ * @param prefixes the caller provided prefixes
+ * @param intent PendingIntent to be sent when a SMS is received containing the token and one
+ * of the prefixes
+ */
+ String createAppSpecificSmsTokenWithPackageInfo(
+ int subId, String callingPkg, String prefixes, in PendingIntent intent);
}
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 1cdf44d..f2f2960 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -188,4 +188,10 @@
public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String createAppSpecificSmsTokenWithPackageInfo(
+ int subId, String callingPkg, String prefixes, PendingIntent intent) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk
index 979d13a..ee02a72 100644
--- a/tests/DexLoggerIntegrationTests/Android.mk
+++ b/tests/DexLoggerIntegrationTests/Android.mk
@@ -35,7 +35,6 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := DexLoggerNativeTestLibrary
-LOCAL_MULTILIB := first
LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
@@ -44,8 +43,6 @@
include $(BUILD_SHARED_LIBRARY)
-dexloggertest_so := $(LOCAL_BUILT_MODULE)
-
# And a standalone native executable that we can exec.
include $(CLEAR_VARS)
@@ -73,11 +70,15 @@
android-support-test \
truth-prebuilt \
+# Include both versions of the .so if we have 2 arch
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := \
+ DexLoggerNativeTestLibrary \
+
# This gets us the javalib.jar built by DexLoggerTestLibrary above as well as the various
# native binaries.
LOCAL_JAVA_RESOURCE_FILES := \
$(dexloggertest_jar) \
- $(dexloggertest_so) \
- $(dexloggertest_executable)
+ $(dexloggertest_executable) \
include $(BUILD_PACKAGE)
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 d68769b..e92cc56 100644
--- a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
+++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
@@ -21,6 +21,7 @@
import android.app.UiAutomation;
import android.content.Context;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
@@ -147,7 +148,7 @@
String expectedNameHash =
"996223BAD4B4FE75C57A3DEC61DB9C0B38E0A7AD479FC95F33494F4BC55A0F0E";
String expectedContentHash =
- copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+ copyAndHashResource(libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
System.load(privateCopyFile.toString());
@@ -170,7 +171,7 @@
String expectedNameHash =
"8C39990C560B4F36F83E208E279F678746FE23A790E4C50F92686584EA2041CA";
String expectedContentHash =
- copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+ copyAndHashResource(libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
System.load(privateCopyFile.toString());
@@ -307,6 +308,12 @@
return new File(sContext.getDir("dcl", Context.MODE_PRIVATE), name);
}
+ private String libraryPath(final String libraryName) {
+ // This may be deprecated. but it tells us the ABI of this process which is exactly what we
+ // want.
+ return "/lib/" + Build.CPU_ABI + "/" + libraryName;
+ }
+
private static String copyAndHashResource(String resourcePath, File copyTo) throws Exception {
MessageDigest hasher = MessageDigest.getInstance("SHA-256");
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
index 030641b..e10f866 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
@@ -29,7 +29,7 @@
/**
* A broadcast receiver that can be used to get
- * ACTION_PACKAGE_ROLLBACK_EXECUTED broadcasts.
+ * ACTION_ROLLBACK_COMMITTED broadcasts.
*/
class RollbackBroadcastReceiver extends BroadcastReceiver {
@@ -43,7 +43,7 @@
*/
RollbackBroadcastReceiver() {
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+ filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED);
InstrumentationRegistry.getContext().registerReceiver(this, filter);
}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 13ac4f0..7ab716f 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -31,11 +31,8 @@
import android.util.Log;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Ignore;
@@ -43,6 +40,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -86,8 +84,8 @@
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS);
- // Register a broadcast receiver for notification when the rollback is
- // done executing.
+ // Register a broadcast receiver for notification when the
+ // rollback has been committed.
RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -99,12 +97,11 @@
// uninstalled and when rollback manager deletes the rollback. Fix it
// so that's not the case!
for (int i = 0; i < 5; ++i) {
- for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(info.targetPackage.getPackageName())) {
- Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
- Thread.sleep(1000);
- break;
- }
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ if (rollback != null) {
+ Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
+ Thread.sleep(1000);
}
}
@@ -113,13 +110,11 @@
// between when the app is uninstalled and when the previously
// available rollback, if any, is removed.
Thread.sleep(1000);
- assertNull(rm.getAvailableRollback(TEST_APP_A));
- assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
- // There should be no recently executed rollbacks for this package.
- for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
- assertNotEquals(TEST_APP_A, info.targetPackage.getPackageName());
- }
+ // There should be no recently committed rollbacks for this package.
+ assertNull(getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A));
// Install v1 of the app (without rollbacks enabled).
RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -134,10 +129,9 @@
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
// We should not have received any rollback requests yet.
// TODO: Possibly flaky if, by chance, some other app on device
@@ -156,15 +150,9 @@
assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
// Verify the recent rollback has been recorded.
- rollback = null;
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
- assertNull(rollback);
- rollback = r;
- }
- }
- assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
broadcastReceiver.unregister();
context.unregisterReceiver(enableRollbackReceiver);
@@ -202,28 +190,25 @@
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Reload the persisted data.
rm.reloadPersistedData();
// The apps should still be available for rollback.
- rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Rollback of B should not rollback A
RollbackTestUtils.rollback(rollbackB);
@@ -264,28 +249,23 @@
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoForAandB(rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoForAandB(rollbackB);
// Reload the persisted data.
rm.reloadPersistedData();
// The apps should still be available for rollback.
- rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ rollbackA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoForAandB(rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ rollbackB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoForAandB(rollbackB);
// Rollback of B should rollback A as well
RollbackTestUtils.rollback(rollbackB);
@@ -297,10 +277,10 @@
}
/**
- * Test that recently executed rollback data is properly persisted.
+ * Test that recently committed rollback data is properly persisted.
*/
@Test
- public void testRecentlyExecutedRollbackPersistence() throws Exception {
+ public void testRecentlyCommittedRollbackPersistence() throws Exception {
try {
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
@@ -319,37 +299,27 @@
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
// Roll back the app.
RollbackTestUtils.rollback(rollback);
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
// Verify the recent rollback has been recorded.
- rollback = null;
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
- assertNull(rollback);
- rollback = r;
- }
- }
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
// Reload the persisted data.
rm.reloadPersistedData();
// Verify the recent rollback is still recorded.
- rollback = null;
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
- assertNull(rollback);
- rollback = r;
- }
- }
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -378,17 +348,16 @@
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
// Expire the rollback.
rm.expireRollbackForPackage(TEST_APP_A);
// The rollback should no longer be available.
- assertNull(rm.getAvailableRollback(TEST_APP_A));
- assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ assertNull(getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A));
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -459,7 +428,8 @@
processUserData(TEST_APP_A);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
RollbackTestUtils.rollback(rollback);
processUserData(TEST_APP_A);
} finally {
@@ -469,12 +439,12 @@
/**
* Test restrictions on rollback broadcast sender.
- * A random app should not be able to send a PACKAGE_ROLLBACK_EXECUTED broadcast.
+ * A random app should not be able to send a ROLLBACK_COMMITTED broadcast.
*/
@Test
public void testRollbackBroadcastRestrictions() throws Exception {
RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
- Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+ Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
try {
InstrumentationRegistry.getContext().sendBroadcast(broadcast);
fail("Succeeded in sending restricted broadcast from app context.");
@@ -516,18 +486,18 @@
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
// Both test apps should now be available for rollback, and the
- // targetPackage returned for rollback should be correct.
+ // RollbackInfo returned for the rollbacks should be correct.
// TODO: See if there is a way to remove this race condition
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Executing rollback should roll back the correct package.
RollbackTestUtils.rollback(rollbackA);
@@ -558,21 +528,14 @@
RollbackManager rm = RollbackTestUtils.getRollbackManager();
try {
- rm.getAvailableRollback(TEST_APP_A);
+ rm.getAvailableRollbacks();
fail("expected SecurityException");
} catch (SecurityException e) {
// Expected.
}
try {
- rm.getPackagesWithAvailableRollbacks();
- fail("expected SecurityException");
- } catch (SecurityException e) {
- // Expected.
- }
-
- try {
- rm.getRecentlyExecutedRollbacks();
+ rm.getRecentlyCommittedRollbacks();
fail("expected SecurityException");
} catch (SecurityException e) {
// Expected.
@@ -581,7 +544,7 @@
try {
// TODO: What if the implementation checks arguments for non-null
// first? Then this test isn't valid.
- rm.executeRollback(null, null);
+ rm.commitRollback(null, null);
fail("expected SecurityException");
} catch (SecurityException e) {
// Expected.
@@ -629,12 +592,9 @@
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
// TEST_APP_A should now be available for rollback.
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollback);
-
- // TODO: Test the dependent apps for rollback are correct once we
- // support that in the RollbackInfo API.
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoForAandB(rollback);
// Rollback the app. It should cause both test apps to be rolled
// back.
@@ -642,14 +602,16 @@
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
- // We should not see a recent rollback listed for TEST_APP_B
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- assertNotEquals(TEST_APP_B, r.targetPackage.getPackageName());
- }
+ // We should see recent rollbacks listed for both A and B.
+ Thread.sleep(1000);
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
- // TODO: Test the listed dependent apps for the recently executed
- // rollback are correct once we support that in the RollbackInfo
- // API.
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_B);
+ assertRollbackInfoForAandB(rollbackB);
+
+ assertEquals(rollbackA.getRollbackId(), rollbackB.getRollbackId());
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -697,13 +659,13 @@
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
for (int i = 0; i < 5; i++) {
@@ -724,4 +686,47 @@
RollbackTestUtils.dropShellPermissionIdentity();
}
}
+
+ // Helper function to test the value of a RollbackInfo with single package
+ private void assertRollbackInfoEquals(String packageName,
+ long versionRolledBackFrom, long versionRolledBackTo,
+ RollbackInfo info) {
+ assertNotNull(info);
+ assertEquals(1, info.getPackages().size());
+ assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
+ info.getPackages().get(0));
+ }
+
+ // 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) {
+ assertNotNull(rollback);
+ assertEquals(2, rollback.getPackages().size());
+ if (TEST_APP_A.equals(rollback.getPackages().get(0).getPackageName())) {
+ assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(0));
+ assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(1));
+ } else {
+ assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(0));
+ 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/src/com/android/tests/rollback/RollbackTestUtils.java
index edb1355..f481897 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -90,12 +90,12 @@
}
/**
- * Execute the given rollback.
+ * Commit the given rollback.
* @throws AssertionError if the rollback fails.
*/
static void rollback(RollbackInfo rollback) throws InterruptedException {
RollbackManager rm = getRollbackManager();
- rm.executeRollback(rollback, LocalIntentSender.getIntentSender());
+ rm.commitRollback(rollback, LocalIntentSender.getIntentSender());
assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
}
diff --git a/tools/bit/aapt.cpp b/tools/bit/aapt.cpp
index 961b47c..cee0cd5 100644
--- a/tools/bit/aapt.cpp
+++ b/tools/bit/aapt.cpp
@@ -159,10 +159,11 @@
inspect_apk(Apk* apk, const string& filename)
{
// Load the manifest xml
- Command cmd("aapt");
+ Command cmd("aapt2");
cmd.AddArg("dump");
cmd.AddArg("xmltree");
cmd.AddArg(filename);
+ cmd.AddArg("--file");
cmd.AddArg("AndroidManifest.xml");
int err;
@@ -217,11 +218,11 @@
if (current != NULL) {
Attribute attr;
string str = match[2];
- size_t colon = str.find(':');
+ size_t colon = str.rfind(':');
if (colon == string::npos) {
attr.name = str;
} else {
- attr.ns = scope->namespaces[string(str, 0, colon)];
+ attr.ns.assign(str, 0, colon);
attr.name.assign(str, colon+1, string::npos);
}
attr.value = match[3];
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index a71cea1..860094ae 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -623,12 +623,13 @@
const string buildProduct = get_required_env("TARGET_PRODUCT", false);
const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
-
+ const string buildOut = get_out_dir();
chdir_or_exit(buildTop.c_str());
- const string buildDevice = get_build_var("TARGET_DEVICE", false);
- const string buildId = get_build_var("BUILD_ID", false);
- const string buildOut = get_out_dir();
+ BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
+
+ const string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
+ const string buildId = buildVars.GetBuildVar("BUILD_ID", false);
// Get the modules for the targets
map<string,Module> modules;
@@ -661,6 +662,7 @@
string dataPath = buildOut + "/target/product/" + buildDevice + "/data/";
bool syncSystem = false;
bool alwaysSyncSystem = false;
+ vector<string> systemFiles;
vector<InstallApk> installApks;
for (size_t i=0; i<targets.size(); i++) {
Target* target = targets[i];
@@ -670,6 +672,7 @@
// System partition
if (starts_with(file, systemPath)) {
syncSystem = true;
+ systemFiles.push_back(file);
if (!target->build) {
// If a system partition target didn't get built then
// it won't change we will always need to do adb sync
@@ -692,6 +695,19 @@
get_directory_contents(systemPath, &systemFilesBefore);
}
+ if (systemFiles.size() > 0){
+ print_info("System files:");
+ for (size_t i=0; i<systemFiles.size(); i++) {
+ printf(" %s\n", systemFiles[i].c_str());
+ }
+ }
+ if (installApks.size() > 0){
+ print_info("APKs to install:");
+ for (size_t i=0; i<installApks.size(); i++) {
+ printf(" %s\n", installApks[i].file.filename.c_str());
+ }
+ }
+
//
// Build
//
@@ -798,7 +814,8 @@
for (size_t j=0; j<target->module.installed.size(); j++) {
string filename = target->module.installed[j];
- if (!ends_with(filename, ".apk")) {
+ // Apk in the data partition
+ if (!starts_with(filename, dataPath) || !ends_with(filename, ".apk")) {
continue;
}
@@ -1004,13 +1021,16 @@
void
run_tab_completion(const string& word)
{
- const string buildTop = get_required_env("ANDROID_BUILD_TOP", true);
+ const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
const string buildProduct = get_required_env("TARGET_PRODUCT", false);
+ const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
+ const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
const string buildOut = get_out_dir();
-
chdir_or_exit(buildTop.c_str());
- string buildDevice = sniff_device_name(buildOut, buildProduct);
+ BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
+
+ string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
map<string,Module> modules;
read_modules(buildOut, buildDevice, &modules, true);
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index 5a9ab22..6270913 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -21,6 +21,7 @@
#include "util.h"
#include <json/reader.h>
+#include <json/writer.h>
#include <json/value.h>
#include <fstream>
@@ -34,22 +35,118 @@
using namespace std;
-map<string,string> g_buildVars;
+static bool
+map_contains(const map<string,string>& m, const string& k, const string& v) {
+ map<string,string>::const_iterator it = m.find(k);
+ if (it == m.end()) {
+ return false;
+ }
+ return it->second == v;
+}
+
+static string
+make_cache_filename(const string& outDir)
+{
+ string filename(outDir);
+ return filename + "/.bit_cache";
+}
+
+BuildVars::BuildVars(const string& outDir, const string& buildProduct,
+ const string& buildVariant, const string& buildType)
+ :m_filename(),
+ m_cache()
+{
+ m_cache["TARGET_PRODUCT"] = buildProduct;
+ m_cache["TARGET_BUILD_VARIANT"] = buildVariant;
+ m_cache["TARGET_BUILD_TYPE"] = buildType;
+
+ // If we have any problems reading the file, that's ok, just do
+ // uncached calls to make / soong.
+
+ if (outDir == "") {
+ return;
+ }
+
+
+ m_filename = make_cache_filename(outDir);
+
+ std::ifstream stream(m_filename, std::ifstream::binary);
+
+ if (stream.fail()) {
+ return;
+ }
+
+ Json::Value json;
+ Json::Reader reader;
+ if (!reader.parse(stream, json)) {
+ return;
+ }
+
+ if (!json.isObject()) {
+ return;
+ }
+
+ map<string,string> cache;
+
+ vector<string> names = json.getMemberNames();
+ const int N = names.size();
+ for (int i=0; i<N; i++) {
+ const string& name = names[i];
+ const Json::Value& value = json[name];
+ if (!value.isString()) {
+ continue;
+ }
+ cache[name] = value.asString();
+ }
+
+ // If all of the base variables match, then we can use this cache. Otherwise, use our
+ // base one. The next time someone reads a value, the new one, with our base varaibles
+ // will be saved.
+ if (map_contains(cache, "TARGET_PRODUCT", buildProduct)
+ && map_contains(cache, "TARGET_BUILD_VARIANT", buildVariant)
+ && map_contains(cache, "TARGET_BUILD_TYPE", buildType)) {
+ m_cache = cache;
+ }
+}
+
+BuildVars::~BuildVars()
+{
+}
+
+void
+BuildVars::save()
+{
+ if (m_filename == "") {
+ return;
+ }
+
+ Json::StyledStreamWriter writer(" ");
+
+ Json::Value json(Json::objectValue);
+
+ for (map<string,string>::const_iterator it = m_cache.begin(); it != m_cache.end(); it++) {
+ json[it->first] = it->second;
+ }
+
+ std::ofstream stream(m_filename, std::ofstream::binary);
+ writer.write(stream, json);
+}
string
-get_build_var(const string& name, bool quiet)
+BuildVars::GetBuildVar(const string& name, bool quiet)
{
int err;
- map<string,string>::iterator it = g_buildVars.find(name);
- if (it == g_buildVars.end()) {
+ map<string,string>::iterator it = m_cache.find(name);
+ if (it == m_cache.end()) {
Command cmd("build/soong/soong_ui.bash");
cmd.AddArg("--dumpvar-mode");
cmd.AddArg(name);
string output = trim(get_command_output(cmd, &err, quiet));
if (err == 0) {
- g_buildVars[name] = output;
+ m_cache[name] = output;
+ save();
return output;
} else {
return string();
@@ -59,38 +156,6 @@
}
}
-string
-sniff_device_name(const string& buildOut, const string& product)
-{
- string match("ro.build.product=" + product);
-
- string base(buildOut + "/target/product");
- DIR* dir = opendir(base.c_str());
- if (dir == NULL) {
- return string();
- }
-
- dirent* entry;
- while ((entry = readdir(dir)) != NULL) {
- if (entry->d_name[0] == '.') {
- continue;
- }
- if (entry->d_type == DT_DIR) {
- string filename(base + "/" + entry->d_name + "/system/build.prop");
- vector<string> lines;
- split_lines(&lines, read_file(filename));
- for (size_t i=0; i<lines.size(); i++) {
- if (lines[i] == match) {
- return entry->d_name;
- }
- }
- }
- }
-
- closedir(dir);
- return string();
-}
-
void
json_error(const string& filename, const char* error, bool quiet)
{
diff --git a/tools/bit/make.h b/tools/bit/make.h
index 1c9504d..db0b69f 100644
--- a/tools/bit/make.h
+++ b/tools/bit/make.h
@@ -31,16 +31,26 @@
vector<string> installed;
};
-string get_build_var(const string& name, bool quiet);
-
/**
- * Poke around in the out directory and try to find a device name that matches
- * our product. This is faster than running get_build_var and good enough for
- * tab completion.
- *
- * Returns the empty string if we can't find one.
+ * Class to encapsulate getting build variables. Caches the
+ * results if possible.
*/
-string sniff_device_name(const string& buildOut, const string& product);
+class BuildVars
+{
+public:
+ BuildVars(const string& outDir, const string& buildProduct,
+ const string& buildVariant, const string& buildType);
+ ~BuildVars();
+
+ string GetBuildVar(const string& name, bool quiet);
+
+private:
+ void save();
+
+ string m_filename;
+
+ map<string,string> m_cache;
+};
void read_modules(const string& buildOut, const string& buildDevice,
map<string,Module>* modules, bool quiet);
diff --git a/tools/bit/print.cpp b/tools/bit/print.cpp
index 790e0b4..35feda1 100644
--- a/tools/bit/print.cpp
+++ b/tools/bit/print.cpp
@@ -116,6 +116,20 @@
}
void
+print_info(const char* format, ...)
+{
+ fputs(g_escapeBold, stdout);
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+
+ fputs(g_escapeEndColor, stdout);
+ fputc('\n', stdout);
+}
+
+void
print_one_line(const char* format, ...)
{
if (g_stdoutIsTty) {
diff --git a/tools/bit/print.h b/tools/bit/print.h
index b6c3e9a..db6cf5f 100644
--- a/tools/bit/print.h
+++ b/tools/bit/print.h
@@ -33,6 +33,7 @@
void print_command(const Command& command);
void print_error(const char* format, ...);
void print_warning(const char* format, ...);
+void print_info(const char* format, ...);
void print_one_line(const char* format, ...);
void check_error(int err);