Merge "Camera: Switch the reader callback when the sequence ends" into sc-dev
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 8723515..8fcd2f9 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -146,19 +146,17 @@
* <p>It is a no-op to set the same schema as has been previously set; this is handled
* efficiently.
*
- * <p>By default, documents are visible on platform surfaces. To opt out, call {@code
- * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
- * visibility settings apply only to the schemas that are included in the {@code request}.
- * Visibility settings for a schema type do not apply or persist across
- * {@link SetSchemaRequest}s.
+ * <p>By default, documents are visible on platform surfaces. To opt out, call
+ * {@link SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} with {@code visible} as
+ * false. Any visibility settings apply only to the schemas that are included in the
+ * {@code request}. Visibility settings for a schema type do not persist across
+ * {@link #setSchema} calls.
*
* @param request The schema update request.
* @param executor Executor on which to invoke the callback.
* @param callback Callback to receive errors resulting from setting the schema. If the
* operation succeeds, the callback will be invoked with {@code null}.
*/
- // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
- // exposed.
public void setSchema(
@NonNull SetSchemaRequest request,
@NonNull @CallbackExecutor Executor executor,
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index c369801..a45fa39 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -41,6 +41,7 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -58,8 +59,11 @@
private PackageManagerInternal mPackageManagerInternal;
private ImplInstanceManager mImplInstanceManager;
- // Cache of unlocked user ids so we don't have to query UserManager service each time.
- private final Set<Integer> mUnlockedUserIds = new ArraySet<>();
+ // Cache of unlocked user ids so we don't have to query UserManager service each time. The
+ // "locked" suffix refers to the fact that access to the field should be locked; unrelated to
+ // the unlocked status of user ids.
+ @GuardedBy("mUnlockedUserIdsLocked")
+ private final Set<Integer> mUnlockedUserIdsLocked = new ArraySet<>();
public AppSearchManagerService(Context context) {
super(context);
@@ -74,7 +78,9 @@
@Override
public void onUserUnlocked(@NonNull TargetUser user) {
- mUnlockedUserIds.add(user.getUserIdentifier());
+ synchronized (mUnlockedUserIdsLocked) {
+ mUnlockedUserIdsLocked.add(user.getUserIdentifier());
+ }
}
private class Stub extends IAppSearchManager.Stub {
@@ -503,9 +509,11 @@
}
private void verifyUserUnlocked(int callingUserId) {
- if (!mUnlockedUserIds.contains(callingUserId)) {
- throw new IllegalStateException(
- "User " + callingUserId + " is locked or not running.");
+ synchronized (mUnlockedUserIdsLocked) {
+ if (!mUnlockedUserIdsLocked.contains(callingUserId)) {
+ throw new IllegalStateException(
+ "User " + callingUserId + " is locked or not running.");
+ }
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index 5ea2a02..82319d4 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -29,6 +29,7 @@
import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import java.io.File;
@@ -43,7 +44,9 @@
private static ImplInstanceManager sImplInstanceManager;
- private final SparseArray<AppSearchImpl> mInstances = new SparseArray<>();
+ @GuardedBy("mInstancesLocked")
+ private final SparseArray<AppSearchImpl> mInstancesLocked = new SparseArray<>();
+
private final String mGlobalQuerierPackage;
private ImplInstanceManager(@NonNull String globalQuerierPackage) {
@@ -81,19 +84,16 @@
* @return An initialized {@link AppSearchImpl} for this user
*/
@NonNull
- public AppSearchImpl getAppSearchImpl(@NonNull Context context, @UserIdInt int userId)
- throws AppSearchException {
- AppSearchImpl instance = mInstances.get(userId);
- if (instance == null) {
- synchronized (ImplInstanceManager.class) {
- instance = mInstances.get(userId);
- if (instance == null) {
- instance = createImpl(context, userId);
- mInstances.put(userId, instance);
- }
+ public AppSearchImpl getAppSearchImpl(
+ @NonNull Context context, @UserIdInt int userId) throws AppSearchException {
+ synchronized (mInstancesLocked) {
+ AppSearchImpl instance = mInstancesLocked.get(userId);
+ if (instance == null) {
+ instance = createImpl(context, userId);
+ mInstancesLocked.put(userId, instance);
}
+ return instance;
}
- return instance;
}
private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
index 64dc972..babcd25 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
@@ -332,10 +332,8 @@
for (Map.Entry<String, List<PackageIdentifier>> entry :
schemasPackageAccessible.entrySet()) {
for (int i = 0; i < entry.getValue().size(); i++) {
- // TODO(b/169883602): remove the "placeholder" uri once upstream changes to relax
- // nested document uri rules gets synced down.
GenericDocument packageAccessibleDocument =
- new GenericDocument.Builder(/*uri=*/ "placeholder", PACKAGE_ACCESSIBLE_TYPE)
+ new GenericDocument.Builder(/*uri=*/"", PACKAGE_ACCESSIBLE_TYPE)
.setNamespace(NAMESPACE)
.setPropertyString(
PACKAGE_NAME_PROPERTY,
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index 8e62c0e..b2ffd5b 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -86,11 +86,11 @@
* <p>It is a no-op to set the same schema as has been previously set; this is handled
* efficiently.
*
- * <p>By default, documents are visible on platform surfaces. To opt out, call {@code
- * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
- * visibility settings apply only to the schemas that are included in the {@code request}.
- * Visibility settings for a schema type do not apply or persist across {@link
- * SetSchemaRequest}s.
+ * <p>By default, documents are visible on platform surfaces. To opt out, call
+ * {@link SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} with {@code visible} as
+ * false. Any visibility settings apply only to the schemas that are included in the
+ * {@code request}. Visibility settings for a schema type do not persist across
+ * {@link #setSchema} calls.
*
* <p>Migration: make non-backwards-compatible changes will delete all stored documents in old
* schema. You can save your documents by setting {@link
@@ -116,8 +116,6 @@
* @see android.app.appsearch.AppSearchSchema.Migrator
* @see android.app.appsearch.AppSearchMigrationHelper.Transformer
*/
- // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
- // exposed.
@NonNull
ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 82e967a..3cefe65 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -64,7 +64,7 @@
* and which {@link JobServiceContext} to run each job on.
*/
class JobConcurrencyManager {
- private static final String TAG = JobSchedulerService.TAG;
+ private static final String TAG = JobSchedulerService.TAG + ".Concurrency";
private static final boolean DEBUG = JobSchedulerService.DEBUG;
static final String CONFIG_KEY_PREFIX_CONCURRENCY = "concurrency_";
@@ -321,13 +321,14 @@
}
}
+ /** Return {@code true} if the state was updated. */
@GuardedBy("mLock")
- private void refreshSystemStateLocked() {
+ private boolean refreshSystemStateLocked() {
final long nowUptime = JobSchedulerService.sUptimeMillisClock.millis();
// Only refresh the information every so often.
if (nowUptime < mNextSystemStateRefreshTime) {
- return;
+ return false;
}
final long start = mStatLogger.getTime();
@@ -340,11 +341,14 @@
}
mStatLogger.logDurationStat(Stats.REFRESH_SYSTEM_STATE, start);
+ return true;
}
@GuardedBy("mLock")
private void updateCounterConfigLocked() {
- refreshSystemStateLocked();
+ if (!refreshSystemStateLocked()) {
+ return;
+ }
final WorkConfigLimitsPerMemoryTrimLevel workConfigs = mEffectiveInteractiveState
? CONFIG_LIMITS_SCREEN_ON : CONFIG_LIMITS_SCREEN_OFF;
@@ -437,9 +441,10 @@
// (sharing the same Uid as nextPending)
int minPriorityForPreemption = Integer.MAX_VALUE;
int selectedContextId = -1;
- int workType = mWorkCountTracker.canJobStart(getJobWorkTypes(nextPending));
+ int allWorkTypes = getJobWorkTypes(nextPending);
+ int workType = mWorkCountTracker.canJobStart(allWorkTypes);
boolean startingJob = false;
- for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) {
+ for (int j = 0; j < MAX_JOB_CONTEXTS_COUNT; j++) {
JobStatus job = contextIdToJobMap[j];
int preferredUid = preferredUidForContext[j];
if (job == null) {
@@ -483,7 +488,7 @@
if (startingJob) {
// Increase the counters when we're going to start a job.
workTypeForContext[selectedContextId] = workType;
- mWorkCountTracker.stageJob(workType);
+ mWorkCountTracker.stageJob(workType, allWorkTypes);
}
}
if (DEBUG) {
@@ -578,8 +583,10 @@
JobStatus highestPriorityJob = null;
int highPriWorkType = workType;
+ int highPriAllWorkTypes = workType;
JobStatus backupJob = null;
int backupWorkType = WORK_TYPE_NONE;
+ int backupAllWorkTypes = WORK_TYPE_NONE;
for (int i = 0; i < pendingJobs.size(); i++) {
final JobStatus nextPending = pendingJobs.get(i);
@@ -589,11 +596,12 @@
if (worker.getPreferredUid() != nextPending.getUid()) {
if (backupJob == null) {
- int workAsType =
- mWorkCountTracker.canJobStart(getJobWorkTypes(nextPending));
+ int allWorkTypes = getJobWorkTypes(nextPending);
+ int workAsType = mWorkCountTracker.canJobStart(allWorkTypes);
if (workAsType != WORK_TYPE_NONE) {
backupJob = nextPending;
backupWorkType = workAsType;
+ backupAllWorkTypes = allWorkTypes;
}
}
continue;
@@ -611,7 +619,8 @@
// reserved slots. We should just run the highest priority job we can find,
// though it would be ideal to use an available WorkType slot instead of
// overloading slots.
- final int workAsType = mWorkCountTracker.canJobStart(getJobWorkTypes(nextPending));
+ highPriAllWorkTypes = getJobWorkTypes(nextPending);
+ final int workAsType = mWorkCountTracker.canJobStart(highPriAllWorkTypes);
if (workAsType == WORK_TYPE_NONE) {
// Just use the preempted job's work type since this new one is technically
// replacing it anyway.
@@ -624,7 +633,7 @@
if (DEBUG) {
Slog.d(TAG, "Running job " + jobStatus + " as preemption");
}
- mWorkCountTracker.stageJob(highPriWorkType);
+ mWorkCountTracker.stageJob(highPriWorkType, highPriAllWorkTypes);
startJobLocked(worker, highestPriorityJob, highPriWorkType);
} else {
if (DEBUG) {
@@ -635,7 +644,7 @@
if (DEBUG) {
Slog.d(TAG, "Running job " + jobStatus + " instead");
}
- mWorkCountTracker.stageJob(backupWorkType);
+ mWorkCountTracker.stageJob(backupWorkType, backupAllWorkTypes);
startJobLocked(worker, backupJob, backupWorkType);
}
}
@@ -647,6 +656,7 @@
// find.
JobStatus highestPriorityJob = null;
int highPriWorkType = workType;
+ int highPriAllWorkTypes = workType;
for (int i = 0; i < pendingJobs.size(); i++) {
final JobStatus nextPending = pendingJobs.get(i);
@@ -654,7 +664,8 @@
continue;
}
- final int workAsType = mWorkCountTracker.canJobStart(getJobWorkTypes(nextPending));
+ final int allWorkTypes = getJobWorkTypes(nextPending);
+ final int workAsType = mWorkCountTracker.canJobStart(allWorkTypes);
if (workAsType == WORK_TYPE_NONE) {
continue;
}
@@ -663,6 +674,7 @@
< nextPending.lastEvaluatedPriority) {
highestPriorityJob = nextPending;
highPriWorkType = workAsType;
+ highPriAllWorkTypes = allWorkTypes;
}
}
@@ -672,7 +684,7 @@
if (DEBUG) {
Slog.d(TAG, "About to run job: " + jobStatus);
}
- mWorkCountTracker.stageJob(highPriWorkType);
+ mWorkCountTracker.stageJob(highPriWorkType, highPriAllWorkTypes);
startJobLocked(worker, highestPriorityJob, highPriWorkType);
}
}
@@ -1102,26 +1114,58 @@
}
void incrementPendingJobCount(int workTypes) {
- // We don't know which type we'll classify the job as when we run it yet, so make sure
- // we have space in all applicable slots.
- if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
- mNumPendingJobs.put(WORK_TYPE_TOP, mNumPendingJobs.get(WORK_TYPE_TOP) + 1);
- }
- if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
- mNumPendingJobs.put(WORK_TYPE_EJ, mNumPendingJobs.get(WORK_TYPE_EJ) + 1);
- }
- if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
- mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + 1);
- }
- if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
- mNumPendingJobs.put(WORK_TYPE_BGUSER, mNumPendingJobs.get(WORK_TYPE_BGUSER) + 1);
+ adjustPendingJobCount(workTypes, true);
+ }
+
+ void decrementPendingJobCount(int workTypes) {
+ if (adjustPendingJobCount(workTypes, false) > 1) {
+ // We don't need to adjust reservations if only one work type was modified
+ // because that work type is the one we're using.
+
+ // 0 is WORK_TYPE_NONE.
+ int workType = 1;
+ int rem = workTypes;
+ while (rem > 0) {
+ if ((rem & 1) != 0) {
+ maybeAdjustReservations(workType);
+ }
+ rem = rem >>> 1;
+ workType = workType << 1;
+ }
}
}
- void stageJob(@WorkType int workType) {
+ /** Returns the number of WorkTypes that were modified. */
+ private int adjustPendingJobCount(int workTypes, boolean add) {
+ final int adj = add ? 1 : -1;
+
+ int numAdj = 0;
+ // We don't know which type we'll classify the job as when we run it yet, so make sure
+ // we have space in all applicable slots.
+ if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
+ mNumPendingJobs.put(WORK_TYPE_TOP, mNumPendingJobs.get(WORK_TYPE_TOP) + adj);
+ numAdj++;
+ }
+ if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
+ mNumPendingJobs.put(WORK_TYPE_EJ, mNumPendingJobs.get(WORK_TYPE_EJ) + adj);
+ numAdj++;
+ }
+ if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
+ mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + adj);
+ numAdj++;
+ }
+ if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
+ mNumPendingJobs.put(WORK_TYPE_BGUSER, mNumPendingJobs.get(WORK_TYPE_BGUSER) + adj);
+ numAdj++;
+ }
+
+ return numAdj;
+ }
+
+ void stageJob(@WorkType int workType, int allWorkTypes) {
final int newNumStartingJobs = mNumStartingJobs.get(workType) + 1;
mNumStartingJobs.put(workType, newNumStartingJobs);
- mNumPendingJobs.put(workType, Math.max(0, mNumPendingJobs.get(workType) - 1));
+ decrementPendingJobCount(allWorkTypes);
if (newNumStartingJobs + mNumRunningJobs.get(workType)
> mNumActuallyReservedSlots.get(workType)) {
mNumUnspecializedRemaining--;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 71fe55f..96f3bcc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3183,7 +3183,7 @@
TimeUtils.formatDuration(jsc.getTimeoutElapsed() - nowElapsed, pw);
pw.println();
job.dump(pw, " ", false, nowElapsed);
- int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
+ int priority = evaluateJobPriorityLocked(job);
pw.print(" Evaluated priority: ");
pw.println(JobInfo.getPriorityString(priority));
@@ -3349,7 +3349,7 @@
job.dump(proto, ActiveJob.RunningJob.DUMP, false, nowElapsed);
proto.write(ActiveJob.RunningJob.EVALUATED_PRIORITY,
- evaluateJobPriorityLocked(jsc.getRunningJobLocked()));
+ evaluateJobPriorityLocked(job));
proto.write(ActiveJob.RunningJob.TIME_SINCE_MADE_ACTIVE_MS,
nowUptime - job.madeActive);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index d15bae0..da6f9fe 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -20,6 +20,7 @@
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import android.annotation.Nullable;
import android.app.job.IJobCallback;
import android.app.job.IJobService;
import android.app.job.JobInfo;
@@ -326,6 +327,7 @@
/**
* Used externally to query the running job. Will return null if there is no job running.
*/
+ @Nullable
JobStatus getRunningJobLocked() {
return mRunningJob;
}
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index 67fa9bb..a2366df 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -8,9 +8,10 @@
method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes();
method @NonNull public java.util.List<java.lang.String> getUnsupportedHdrTypes();
method @NonNull public java.util.List<java.lang.String> getUnsupportedVideoMimeTypes();
- method public boolean isHdrTypeSupported(@NonNull String) throws android.media.ApplicationMediaCapabilities.FormatNotFoundException;
+ method public boolean isFormatSpecified(@NonNull String);
+ method public boolean isHdrTypeSupported(@NonNull String);
method public boolean isSlowMotionSupported();
- method public boolean isVideoMimeTypeSupported(@NonNull String) throws android.media.ApplicationMediaCapabilities.FormatNotFoundException;
+ method public boolean isVideoMimeTypeSupported(@NonNull String);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR;
}
@@ -24,10 +25,6 @@
method @NonNull public android.media.ApplicationMediaCapabilities build();
}
- public static class ApplicationMediaCapabilities.FormatNotFoundException extends android.util.AndroidException {
- ctor public ApplicationMediaCapabilities.FormatNotFoundException(@NonNull String);
- }
-
public class MediaCommunicationManager {
method @IntRange(from=1) public int getVersion();
}
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
index aefeab6..685cf0d 100644
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
@@ -22,7 +22,6 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.AndroidException;
import android.util.Log;
import org.xmlpull.v1.XmlPullParser;
@@ -79,17 +78,7 @@
public final class ApplicationMediaCapabilities implements Parcelable {
private static final String TAG = "ApplicationMediaCapabilities";
- /**
- * This exception is thrown when a given format is not specified in the media capabilities.
- */
- public static class FormatNotFoundException extends AndroidException {
- public FormatNotFoundException(@NonNull String format) {
- super(format);
- }
- }
-
/** List of supported video codec mime types. */
- // TODO: init it with avc and mpeg4 as application is assuming to support them.
private Set<String> mSupportedVideoMimeTypes = new HashSet<>();
/** List of unsupported video codec mime types. */
@@ -113,39 +102,54 @@
/**
* Query if a video codec format is supported by the application.
+ * <p>
+ * If the application has not specified supporting the format or not, this will return false.
+ * Use {@link #isFormatSpecified(String)} to query if a format is specified or not.
+ *
* @param videoMime The mime type of the video codec format. Must be the one used in
* {@link MediaFormat#KEY_MIME}.
* @return true if application supports the video codec format, false otherwise.
- * @throws FormatNotFoundException if the application did not specify the codec either in the
- * supported or unsupported formats.
*/
public boolean isVideoMimeTypeSupported(
- @NonNull String videoMime) throws FormatNotFoundException {
- if (mUnsupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {
- return false;
- } else if (mSupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {
+ @NonNull String videoMime) {
+ if (mSupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {
return true;
- } else {
- throw new FormatNotFoundException(videoMime);
}
+ return false;
}
/**
* Query if a HDR type is supported by the application.
+ * <p>
+ * If the application has not specified supporting the format or not, this will return false.
+ * Use {@link #isFormatSpecified(String)} to query if a format is specified or not.
+ *
* @param hdrType The type of the HDR format.
* @return true if application supports the HDR format, false otherwise.
- * @throws FormatNotFoundException if the application did not specify the format either in the
- * supported or unsupported formats.
*/
public boolean isHdrTypeSupported(
- @NonNull @MediaFeature.MediaHdrType String hdrType) throws FormatNotFoundException {
- if (mUnsupportedHdrTypes.contains(hdrType)) {
- return false;
- } else if (mSupportedHdrTypes.contains(hdrType)) {
+ @NonNull @MediaFeature.MediaHdrType String hdrType) {
+ if (mSupportedHdrTypes.contains(hdrType)) {
return true;
- } else {
- throw new FormatNotFoundException(hdrType);
}
+ return false;
+ }
+
+ /**
+ * Query if a format is specified by the application.
+ * <p>
+ * The format could be either the video format or the hdr format.
+ *
+ * @param format The name of the format.
+ * @return true if application specifies the format, false otherwise.
+ */
+ public boolean isFormatSpecified(@NonNull String format) {
+ if (mSupportedVideoMimeTypes.contains(format) || mUnsupportedVideoMimeTypes.contains(format)
+ || mSupportedHdrTypes.contains(format) || mUnsupportedHdrTypes.contains(format)) {
+ return true;
+
+ }
+ return false;
}
@Override
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index ce7726a..c924d9a 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -1062,14 +1062,8 @@
"Source video format hint must be set!");
}
- boolean supportHevc = false;
- try {
- supportHevc = mClientCaps.isVideoMimeTypeSupported(
- MediaFormat.MIMETYPE_VIDEO_HEVC);
- } catch (ApplicationMediaCapabilities.FormatNotFoundException ex) {
- // Set to false if application did not specify.
- supportHevc = false;
- }
+ boolean supportHevc = mClientCaps.isVideoMimeTypeSupported(
+ MediaFormat.MIMETYPE_VIDEO_HEVC);
if (!supportHevc && MediaFormat.MIMETYPE_VIDEO_HEVC.equals(
mSrcVideoFormatHint.getString(MediaFormat.KEY_MIME))) {
return true;
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ed717c4..4b7eda0 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.UserIdInt;
import android.app.backup.BackupManager;
+import android.app.backup.BackupManager.OperationType;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupProgress;
import android.app.backup.BackupTransport;
@@ -666,7 +667,7 @@
// The rest of the 'list' options work with a restore session on the current transport
try {
- mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
+ mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
if (mRestore == null) {
System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
@@ -821,7 +822,7 @@
try {
boolean didRestore = false;
- mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
+ mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
if (mRestore == null) {
System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
diff --git a/core/api/current.txt b/core/api/current.txt
index 2531d81..dd57b6a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5587,10 +5587,10 @@
field public static final String EXTRA_PROGRESS = "android.progress";
field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
- field public static final String EXTRA_PROMOTE_PICTURE = "android.promotePicture";
field public static final String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft";
field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field @Deprecated public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+ field public static final String EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED = "android.showBigPictureWhenCollapsed";
field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
field @Deprecated public static final String EXTRA_SMALL_ICON = "android.icon";
@@ -6896,6 +6896,7 @@
method public void onLockTaskModeEntering(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull String);
method public void onLockTaskModeExiting(@NonNull android.content.Context, @NonNull android.content.Intent);
method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int);
+ method public void onOperationSafetyStateChanged(@NonNull android.content.Context, int, boolean);
method @Deprecated public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent);
method public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
method @Deprecated public void onPasswordExpiring(@NonNull android.content.Context, @NonNull android.content.Intent);
@@ -7072,6 +7073,7 @@
method public boolean isProfileOwnerApp(String);
method public boolean isProvisioningAllowed(@NonNull String);
method public boolean isResetPasswordTokenActive(android.content.ComponentName);
+ method public boolean isSafeOperation(int);
method public boolean isSecurityLoggingEnabled(@Nullable android.content.ComponentName);
method public boolean isUninstallBlocked(@Nullable android.content.ComponentName, String);
method public boolean isUniqueDeviceAttestationSupported();
@@ -7244,7 +7246,7 @@
field public static final String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
field public static final String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
field public static final String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
- field public static final String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
+ field @Deprecated public static final String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
field public static final String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
field public static final String EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT = "android.app.extra.PROVISIONING_PERMISSION_GRANT_OPT_OUT";
field public static final String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
@@ -7300,6 +7302,7 @@
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
field public static final String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
+ field public static final int OPERATION_SAFETY_REASON_DRIVING_DISTRACTION = 1; // 0x1
field public static final int PASSWORD_COMPLEXITY_HIGH = 327680; // 0x50000
field public static final int PASSWORD_COMPLEXITY_LOW = 65536; // 0x10000
field public static final int PASSWORD_COMPLEXITY_MEDIUM = 196608; // 0x30000
@@ -7336,7 +7339,6 @@
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
- field public static final int UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION = 1; // 0x1
field public static final int WIPE_EUICC = 4; // 0x4
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
@@ -7490,7 +7492,7 @@
public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
method public int describeContents();
- method public int getReason();
+ method @NonNull public java.util.List<java.lang.Integer> getReasons();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UnsafeStateException> CREATOR;
}
@@ -38074,6 +38076,10 @@
method public final void setNotificationsShown(String[]);
method public final void snoozeNotification(String, long);
method public final void updateNotificationChannel(@NonNull String, @NonNull android.os.UserHandle, @NonNull android.app.NotificationChannel);
+ field public static final int FLAG_FILTER_TYPE_ALERTING = 2; // 0x2
+ field public static final int FLAG_FILTER_TYPE_CONVERSATIONS = 1; // 0x1
+ field public static final int FLAG_FILTER_TYPE_ONGOING = 8; // 0x8
+ field public static final int FLAG_FILTER_TYPE_SILENT = 4; // 0x4
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -38082,6 +38088,7 @@
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+ field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types";
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fb6cfea..d7dc6ef 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -905,8 +905,8 @@
field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
field public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
- field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
- field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
+ field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
+ field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
field public static final String EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE = "android.app.extra.PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE";
field public static final String EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER = "android.app.extra.PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER";
@@ -2523,7 +2523,8 @@
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
field public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
- field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
+ field @Deprecated public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
+ field public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = "android.software.incremental_delivery_version";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final String FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION = "android.hardware.telephony.ims.singlereg";
@@ -11949,6 +11950,7 @@
field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1
field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4
field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3
+ field public static final String CAPABILITY_ALLOWED_NETWORK_TYPES_USED = "CAPABILITY_ALLOWED_NETWORK_TYPES_USED";
field public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE = "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE";
field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 909c8e4..694507d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -391,11 +391,11 @@
method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
+ method @NonNull public static String operationSafetyReasonToString(int);
method @NonNull public static String operationToString(int);
method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void resetDefaultCrossProfileIntentFilters(int);
method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, int);
- method @NonNull public static String unsafeOperationReasonToString(int);
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
field public static final int CODE_ACCOUNTS_NOT_EMPTY = 6; // 0x6
field public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11; // 0xb
@@ -425,6 +425,7 @@
field public static final int OPERATION_REMOVE_KEY_PAIR = 28; // 0x1c
field public static final int OPERATION_REMOVE_USER = 6; // 0x6
field public static final int OPERATION_REQUEST_BUGREPORT = 29; // 0x1d
+ field public static final int OPERATION_SAFETY_REASON_NONE = -1; // 0xffffffff
field public static final int OPERATION_SET_ALWAYS_ON_VPN_PACKAGE = 30; // 0x1e
field public static final int OPERATION_SET_APPLICATION_HIDDEN = 15; // 0xf
field public static final int OPERATION_SET_APPLICATION_RESTRICTIONS = 16; // 0x10
@@ -460,7 +461,6 @@
field public static final int PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED = 4; // 0x4
field public static final int PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED = 7; // 0x7
field public static final int PROVISIONING_RESULT_STARTING_PROFILE_FAILED = 5; // 0x5
- field public static final int UNSAFE_OPERATION_REASON_NONE = -1; // 0xffffffff
}
public final class FullyManagedDeviceProvisioningParams implements android.os.Parcelable {
diff --git a/core/java/android/accounts/OWNERS b/core/java/android/accounts/OWNERS
index ea5fd36..8dcc04a 100644
--- a/core/java/android/accounts/OWNERS
+++ b/core/java/android/accounts/OWNERS
@@ -3,7 +3,6 @@
sandrakwan@google.com
hackbod@google.com
svetoslavganov@google.com
-moltmann@google.com
fkupolov@google.com
yamasani@google.com
omakoto@google.com
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 050f34a..b6fc47f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1208,7 +1208,8 @@
* of a {@link BigPictureStyle} notification. This will replace a
* {@link Builder#setLargeIcon(Icon) large icon} in that state if one was provided.
*/
- public static final String EXTRA_PROMOTE_PICTURE = "android.promotePicture";
+ public static final String EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED =
+ "android.showBigPictureWhenCollapsed";
/**
* {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded
@@ -7059,7 +7060,7 @@
private Icon mBigLargeIcon;
private boolean mBigLargeIconSet = false;
private CharSequence mPictureContentDescription;
- private boolean mPromotePicture;
+ private boolean mShowBigPictureWhenCollapsed;
public BigPictureStyle() {
}
@@ -7124,7 +7125,7 @@
*/
@NonNull
public BigPictureStyle showBigPictureWhenCollapsed(boolean show) {
- mPromotePicture = show;
+ mShowBigPictureWhenCollapsed = show;
return this;
}
@@ -7195,7 +7196,7 @@
*/
@Override
public RemoteViews makeContentView(boolean increasedHeight) {
- if (mPicture == null || !mPromotePicture) {
+ if (mPicture == null || !mShowBigPictureWhenCollapsed) {
return super.makeContentView(increasedHeight);
}
@@ -7225,7 +7226,7 @@
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- if (mPicture == null || !mPromotePicture) {
+ if (mPicture == null || !mShowBigPictureWhenCollapsed) {
return super.makeHeadsUpContentView(increasedHeight);
}
@@ -7309,7 +7310,7 @@
extras.putCharSequence(EXTRA_PICTURE_CONTENT_DESCRIPTION,
mPictureContentDescription);
}
- extras.putBoolean(EXTRA_PROMOTE_PICTURE, mPromotePicture);
+ extras.putBoolean(EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED, mShowBigPictureWhenCollapsed);
extras.putParcelable(EXTRA_PICTURE, mPicture);
}
@@ -7330,7 +7331,7 @@
extras.getCharSequence(EXTRA_PICTURE_CONTENT_DESCRIPTION);
}
- mPromotePicture = extras.getBoolean(EXTRA_PROMOTE_PICTURE);
+ mShowBigPictureWhenCollapsed = extras.getBoolean(EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED);
mPicture = extras.getParcelable(EXTRA_PICTURE);
}
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index d175a66..4dbff0c 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -16,6 +16,8 @@
package android.app.admin;
+import static android.app.admin.DevicePolicyManager.OperationSafetyReason;
+
import android.accounts.AccountManager;
import android.annotation.BroadcastBehavior;
import android.annotation.IntDef;
@@ -35,6 +37,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.security.KeyChain;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -72,8 +75,8 @@
* </div>
*/
public class DeviceAdminReceiver extends BroadcastReceiver {
- private static String TAG = "DevicePolicy";
- private static boolean localLOGV = false;
+ private static final String TAG = "DevicePolicy";
+ private static final boolean LOCAL_LOGV = false;
/**
* This is the primary action that a device administrator must implement to be
@@ -509,6 +512,36 @@
public static final String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE =
"android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
+ /**
+ * Broadcast action: notify the admin that the state of operations that can be unsafe because
+ * of a given reason (specified by the {@link #EXTRA_OPERATION_SAFETY_REASON} {@code int} extra)
+ * has changed (the new value is specified by the {@link #EXTRA_OPERATION_SAFETY_STATE}
+ * {@code boolean} extra).
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_OPERATION_SAFETY_STATE_CHANGED =
+ "android.app.action.OPERATION_SAFETY_STATE_CHANGED";
+
+ /**
+ * An {@code int} extra specifying an {@link OperationSafetyReason}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_OPERATION_SAFETY_REASON =
+ "android.app.extra.OPERATION_SAFETY_REASON";
+
+ /**
+ * An {@code boolean} extra specifying whether an operation will fail due to a
+ * {@link OperationSafetyReason}. {@code true} means operations that rely on that reason are
+ * safe, while {@code false} means they're unsafe.
+ *
+ * @hide
+ */
+ public static final String EXTRA_OPERATION_SAFETY_STATE =
+ "android.app.extra.OPERATION_SAFETY_STATE";
+
private DevicePolicyManager mManager;
private ComponentName mWho;
@@ -1018,6 +1051,51 @@
}
/**
+ * Called to notify the state of operations that can be unsafe to execute has changed.
+ *
+ * <p><b>Note:/b> notice that the operation safety state might change between the time this
+ * callback is received and the operation's method on {@link DevicePolicyManager} is called, so
+ * calls to the latter could still throw a {@link UnsafeStateException} even when this method
+ * is called with {@code isSafe} as {@code true}
+ *
+ * @param context the running context as per {@link #onReceive}
+ * @param reason the reason an operation could be unsafe.
+ * @param isSafe whether the operation is safe to be executed.
+ */
+ public void onOperationSafetyStateChanged(@NonNull Context context,
+ @OperationSafetyReason int reason, boolean isSafe) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, String.format("onOperationSafetyStateChanged(): %s=%b",
+ DevicePolicyManager.operationSafetyReasonToString(reason), isSafe));
+ }
+ }
+
+ private void onOperationSafetyStateChanged(Context context, Intent intent) {
+ if (!hasRequiredExtra(intent, EXTRA_OPERATION_SAFETY_REASON)
+ || !hasRequiredExtra(intent, EXTRA_OPERATION_SAFETY_STATE)) {
+ return;
+ }
+
+ int reason = intent.getIntExtra(EXTRA_OPERATION_SAFETY_REASON,
+ DevicePolicyManager.OPERATION_SAFETY_REASON_NONE);
+ if (!DevicePolicyManager.isValidOperationSafetyReason(reason)) {
+ Log.wtf(TAG, "Received invalid reason on " + intent.getAction() + ": " + reason);
+ return;
+ }
+ boolean isSafe = intent.getBooleanExtra(EXTRA_OPERATION_SAFETY_STATE,
+ /* defaultValue=*/ false);
+
+ onOperationSafetyStateChanged(context, reason, isSafe);
+ }
+
+ private boolean hasRequiredExtra(Intent intent, String extra) {
+ if (intent.hasExtra(extra)) return true;
+
+ Log.wtf(TAG, "Missing '" + extra + "' on intent " + intent);
+ return false;
+ }
+
+ /**
* Intercept standard device administrator broadcasts. Implementations
* should not override this method; it is better to implement the
* convenience callbacks for each action.
@@ -1025,6 +1103,9 @@
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
String action = intent.getAction();
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "onReceive(): received " + action + " on user " + context.getUserId());
+ }
if (ACTION_PASSWORD_CHANGED.equals(action)) {
onPasswordChanged(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
@@ -1092,6 +1173,8 @@
} else if (ACTION_AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE.equals(action)) {
onTransferAffiliatedProfileOwnershipComplete(context,
intent.getParcelableExtra(Intent.EXTRA_USER));
+ } else if (ACTION_OPERATION_SAFETY_STATE_CHANGED.equals(action)) {
+ onOperationSafetyStateChanged(context, intent);
}
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ff41d1c8..ff6f6a0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -206,7 +206,6 @@
* {@link android.os.Build.VERSION_CODES#N}</li>
* <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_SKIP_USER_CONSENT}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}, optional</li>
@@ -250,7 +249,6 @@
* <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
* </ul>
*
* <p>If provisioning fails, the device returns to its previous state.
@@ -289,7 +287,6 @@
* <li>{@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS}, optional</li>
* </ul>
@@ -388,8 +385,6 @@
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} (convert to String), optional</li>
* <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOCALE}, optional</li>
@@ -438,8 +433,6 @@
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_SUPPORT_URL}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_ORGANIZATION_NAME}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
@@ -654,7 +647,10 @@
*
* <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} or
* {@link #ACTION_PROVISION_MANAGED_DEVICE}.
+ *
+ * @deprecated Color customization is no longer supported in the provisioning flow.
*/
+ @Deprecated
public static final String EXTRA_PROVISIONING_MAIN_COLOR =
"android.app.extra.PROVISIONING_MAIN_COLOR";
@@ -905,8 +901,10 @@
* <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
* or {@link #ACTION_PROVISION_FINANCED_DEVICE}
*
+ * @deprecated This extra is no longer respected in the provisioning flow.
* @hide
*/
+ @Deprecated
@SystemApi
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL =
"android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
@@ -930,9 +928,11 @@
* <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
* or {@link #ACTION_PROVISION_FINANCED_DEVICE}
*
+ * @deprecated This extra is no longer respected in the provisioning flow.
* @hide
*/
@SystemApi
+ @Deprecated
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI =
"android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
@@ -2922,33 +2922,61 @@
return DebugUtils.constantToString(DevicePolicyManager.class, PREFIX_OPERATION, operation);
}
- private static final String PREFIX_UNSAFE_OPERATION_REASON = "UNSAFE_OPERATION_REASON_";
+ private static final String PREFIX_OPERATION_SAFETY_REASON = "OPERATION_SAFETY_REASON_";
/** @hide */
- @IntDef(prefix = PREFIX_UNSAFE_OPERATION_REASON, value = {
- UNSAFE_OPERATION_REASON_NONE,
- UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION
+ @IntDef(prefix = PREFIX_OPERATION_SAFETY_REASON, value = {
+ OPERATION_SAFETY_REASON_NONE,
+ OPERATION_SAFETY_REASON_DRIVING_DISTRACTION
})
@Retention(RetentionPolicy.SOURCE)
- public static @interface UnsafeOperationReason {
+ public static @interface OperationSafetyReason {
}
/** @hide */
@TestApi
- public static final int UNSAFE_OPERATION_REASON_NONE = -1;
+ public static final int OPERATION_SAFETY_REASON_NONE = -1;
/**
* Indicates that a {@link UnsafeStateException} was thrown because the operation would distract
* the driver of the vehicle.
*/
- public static final int UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION = 1;
+ public static final int OPERATION_SAFETY_REASON_DRIVING_DISTRACTION = 1;
/** @hide */
@NonNull
@TestApi
- public static String unsafeOperationReasonToString(@UnsafeOperationReason int reason) {
+ public static String operationSafetyReasonToString(@OperationSafetyReason int reason) {
return DebugUtils.constantToString(DevicePolicyManager.class,
- PREFIX_UNSAFE_OPERATION_REASON, reason);
+ PREFIX_OPERATION_SAFETY_REASON, reason);
+ }
+
+ /** @hide */
+ public static boolean isValidOperationSafetyReason(@OperationSafetyReason int reason) {
+ return reason == OPERATION_SAFETY_REASON_DRIVING_DISTRACTION;
+ }
+
+ /**
+ * Checks if it's safe to run operations that can be affected by the given {@code reason}.
+ *
+ * <p><b>Note:/b> notice that the operation safety state might change between the time this
+ * method returns and the operation's method is called, so calls to the latter could still throw
+ * a {@link UnsafeStateException} even when this method returns {@code true}.
+ *
+ * @param reason currently, only supported reason is
+ * {@link #OPERATION_SAFETY_REASON_DRIVING_DISTRACTION}.
+ *
+ * @return whether it's safe to run operations that can be affected by the given {@code reason}.
+ */
+ // TODO(b/173541467): should it throw SecurityException if caller is not admin?
+ public boolean isSafeOperation(@OperationSafetyReason int reason) {
+ if (mService == null) return false;
+
+ try {
+ return mService.isSafeOperation(reason);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** @hide */
@@ -13157,7 +13185,7 @@
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
public void setNextOperationSafety(@DevicePolicyOperation int operation,
- @UnsafeOperationReason int reason) {
+ @OperationSafetyReason int reason) {
if (mService != null) {
try {
mService.setNextOperationSafety(operation, reason);
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index a0d2977..67f5c36 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.admin.DevicePolicyManager.OperationSafetyReason;
import android.content.ComponentName;
import android.content.Intent;
import android.os.UserHandle;
@@ -255,4 +256,14 @@
* {@link #supportsResetOp(int)} is true.
*/
public abstract void resetOp(int op, String packageName, @UserIdInt int userId);
+
+ /**
+ * Notifies the system that an unsafe operation reason has changed.
+ *
+ * @throws IllegalArgumentException if {@code checker} is not the same as set on
+ * {@code DevicePolicyManagerService}.
+ */
+ public abstract void notifyUnsafeOperationStateChanged(DevicePolicySafetyChecker checker,
+ @OperationSafetyReason int reason, boolean isSafe);
+
}
diff --git a/core/java/android/app/admin/DevicePolicySafetyChecker.java b/core/java/android/app/admin/DevicePolicySafetyChecker.java
index 6c6f2aa..17b74b1 100644
--- a/core/java/android/app/admin/DevicePolicySafetyChecker.java
+++ b/core/java/android/app/admin/DevicePolicySafetyChecker.java
@@ -17,7 +17,7 @@
import android.annotation.NonNull;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
-import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
+import android.app.admin.DevicePolicyManager.OperationSafetyReason;
import com.android.internal.os.IResultReceiver;
@@ -31,15 +31,20 @@
/**
* Returns whether the given {@code operation} can be safely executed at the moment.
*/
- @UnsafeOperationReason
+ @OperationSafetyReason
int getUnsafeOperationReason(@DevicePolicyOperation int operation);
/**
+ * Return whether it's safe to run operations that can be affected by the given {@code reason}.
+ */
+ boolean isSafeOperation(@OperationSafetyReason int reason);
+
+ /**
* Returns a new exception for when the given {@code operation} cannot be safely executed.
*/
@NonNull
default UnsafeStateException newUnsafeStateException(@DevicePolicyOperation int operation,
- @UnsafeOperationReason int reason) {
+ @OperationSafetyReason int reason) {
return new UnsafeStateException(operation, reason);
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 89f30cc..032cf24 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -492,6 +492,7 @@
boolean canProfileOwnerResetPasswordWhenLocked(int userId);
void setNextOperationSafety(int operation, int reason);
+ boolean isSafeOperation(int reason);
String getEnrollmentSpecificId(String callerPackage);
void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId);
diff --git a/core/java/android/app/admin/UnsafeStateException.java b/core/java/android/app/admin/UnsafeStateException.java
index 56eeb06..f1f6526 100644
--- a/core/java/android/app/admin/UnsafeStateException.java
+++ b/core/java/android/app/admin/UnsafeStateException.java
@@ -15,18 +15,20 @@
*/
package android.app.admin;
-import static android.app.admin.DevicePolicyManager.UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION;
-import static android.app.admin.DevicePolicyManager.unsafeOperationReasonToString;
+import static android.app.admin.DevicePolicyManager.isValidOperationSafetyReason;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
-import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
+import android.app.admin.DevicePolicyManager.OperationSafetyReason;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Exception thrown when a {@link android.app.admin.DevicePolicyManager} operation failed because it
* was not safe to be executed at that moment.
@@ -39,17 +41,15 @@
public final class UnsafeStateException extends IllegalStateException implements Parcelable {
private final @DevicePolicyOperation int mOperation;
- private final @UnsafeOperationReason int mReason;
+ private final @OperationSafetyReason int mReason;
/** @hide */
@TestApi
public UnsafeStateException(@DevicePolicyOperation int operation,
- @UnsafeOperationReason int reason) {
+ @OperationSafetyReason int reason) {
super();
- Preconditions.checkArgument(reason == UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION,
- "invalid reason %d, must be %d (%s)", reason,
- UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION,
- unsafeOperationReasonToString(UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION));
+ Preconditions.checkArgument(isValidOperationSafetyReason(reason), "invalid reason %d",
+ reason);
mOperation = operation;
mReason = reason;
}
@@ -61,19 +61,20 @@
}
/**
- * Gets the reason the operation is unsafe.
+ * Gets the reasons the operation is unsafe.
*
* @return currently, only valid reason is
- * {@link android.app.admin.DevicePolicyManager#UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION}.
+ * {@link android.app.admin.DevicePolicyManager#OPERATION_SAFETY_REASON_DRIVING_DISTRACTION}.
*/
- public @UnsafeOperationReason int getReason() {
- return mReason;
+ @NonNull
+ public List<Integer> getReasons() {
+ return Arrays.asList(mReason);
}
/** @hide */
@Override
public String getMessage() {
- return DevicePolicyManager.unsafeOperationReasonToString(mReason);
+ return DevicePolicyManager.operationSafetyReasonToString(mReason);
}
@Override
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index dae565e..673de8f 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -361,7 +361,36 @@
try {
// All packages, current transport
IRestoreSession binder =
- sService.beginRestoreSessionForUser(mContext.getUserId(), null, null);
+ sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
+ OperationType.BACKUP);
+ if (binder != null) {
+ session = new RestoreSession(mContext, binder);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "beginRestoreSession() couldn't connect");
+ }
+ }
+ return session;
+ }
+
+ /**
+ * Begin the process of restoring data from backup. See the
+ * {@link android.app.backup.RestoreSession} class for documentation on that process.
+ *
+ * @param operationType Type of the operation, see {@link OperationType}
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ public RestoreSession beginRestoreSession(@OperationType int operationType) {
+ RestoreSession session = null;
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ // All packages, current transport
+ IRestoreSession binder =
+ sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
+ operationType);
if (binder != null) {
session = new RestoreSession(mContext, binder);
}
@@ -772,7 +801,7 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.BACKUP)
public int requestBackup(String[] packages, BackupObserver observer) {
- return requestBackup(packages, observer, null, 0);
+ return requestBackup(packages, observer, null, 0, OperationType.BACKUP);
}
/**
@@ -797,6 +826,31 @@
@RequiresPermission(android.Manifest.permission.BACKUP)
public int requestBackup(String[] packages, BackupObserver observer,
BackupManagerMonitor monitor, int flags) {
+ return requestBackup(packages, observer, monitor, flags, OperationType.BACKUP);
+ }
+
+ /**
+ * Request an immediate backup, providing an observer to which results of the backup operation
+ * will be published. The Android backup system will decide for each package whether it will
+ * be full app data backup or key/value-pair-based backup.
+ *
+ * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
+ * provided packages using the remote transport.
+ *
+ * @param packages List of package names to backup.
+ * @param observer The {@link BackupObserver} to receive callbacks during the backup
+ * operation. Could be {@code null}.
+ * @param monitor The {@link BackupManagerMonitorWrapper} to receive callbacks of important
+ * events during the backup operation. Could be {@code null}.
+ * @param flags {@link #FLAG_NON_INCREMENTAL_BACKUP}.
+ * @param operationType {@link OperationType}
+ * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
+ * @throws IllegalArgumentException on null or empty {@code packages} param.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ public int requestBackup(String[] packages, BackupObserver observer,
+ BackupManagerMonitor monitor, int flags, @OperationType int operationType) {
checkServiceBinder();
if (sService != null) {
try {
@@ -806,7 +860,8 @@
BackupManagerMonitorWrapper monitorWrapper = monitor == null
? null
: new BackupManagerMonitorWrapper(monitor);
- return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags);
+ return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags,
+ operationType);
} catch (RemoteException e) {
Log.e(TAG, "requestBackup() couldn't connect");
}
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index bf5be95..e1bbc08 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -547,9 +547,11 @@
* set can be restored.
* @param transportID The name of the transport to use for the restore operation.
* May be null, in which case the current active transport is used.
+ * @param operationType Type of the operation, see {@link BackupManager#OperationType}
* @return An interface to the restore session, or null on error.
*/
- IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID);
+ IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID,
+ int operationType);
/**
* Notify the backup manager that a BackupAgent has completed the operation
@@ -678,7 +680,7 @@
* {@link android.app.backup.IBackupManager.requestBackupForUser} for the calling user id.
*/
int requestBackup(in String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor,
- int flags);
+ int flags, int operationType);
/**
* Cancel all running backups. After this call returns, no currently running backups will
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6cfcce3..a3c3500 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3592,9 +3592,12 @@
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
* the requisite kernel support to support incremental delivery aka Incremental FileSystem.
*
- * @see IncrementalManager#isEnabled
+ * @see IncrementalManager#isFeatureEnabled
* @hide
+ *
+ * @deprecated Use {@link #FEATURE_INCREMENTAL_DELIVERY_VERSION} instead.
*/
+ @Deprecated
@SystemApi
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_INCREMENTAL_DELIVERY =
@@ -3602,6 +3605,20 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * feature not present - IncFs is not present on the device.
+ * 1 - IncFs v1, core features, no PerUid support. Optional in R.
+ * 2 - IncFs v2, PerUid support, fs-verity support. Required in S.
+ *
+ * @see IncrementalManager#isFeatureEnabled and IncrementalManager#isV2()
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION =
+ "android.software.incremental_delivery_version";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device has tuner hardware to support tuner operations.
*
* <p>This feature implies that the device has the tuner HAL implementation.
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index a2e533a..0e70a3e 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -28,6 +28,9 @@
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForStringSet;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Set;
@@ -477,6 +480,8 @@
*/
public @Nullable CharSequence nonLocalizedDescription;
+ private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class);
+
/**
* A {@link Set} of trusted signing certificate digests. If this permission has the {@link
* #PROTECTION_FLAG_KNOWN_SIGNER} flag set the permission will be granted to a requesting app
@@ -688,6 +693,7 @@
dest.writeInt(descriptionRes);
dest.writeInt(requestRes);
TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
+ sForStringSet.parcel(knownCerts, dest, parcelableFlags);
}
/** @hide */
@@ -753,5 +759,6 @@
descriptionRes = source.readInt();
requestRes = source.readInt();
nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ knownCerts = sForStringSet.unparcel(source);
}
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermission.java b/core/java/android/content/pm/parsing/component/ParsedPermission.java
index 35bb33c..37e0e87 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermission.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermission.java
@@ -21,16 +21,22 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+import com.android.internal.util.Parcelling.BuiltIn.ForStringSet;
+import java.util.Locale;
import java.util.Set;
/** @hide */
public class ParsedPermission extends ParsedComponent {
+ private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class);
+
@Nullable
String backgroundPermission;
@Nullable
@@ -89,6 +95,19 @@
return knownCerts;
}
+ protected void setKnownCert(String knownCert) {
+ // Convert the provided digest to upper case for consistent Set membership
+ // checks when verifying the signing certificate digests of requesting apps.
+ this.knownCerts = Set.of(knownCert.toUpperCase(Locale.US));
+ }
+
+ protected void setKnownCerts(String[] knownCerts) {
+ this.knownCerts = new ArraySet<>();
+ for (String knownCert : knownCerts) {
+ this.knownCerts.add(knownCert.toUpperCase(Locale.US));
+ }
+ }
+
public int calculateFootprint() {
int size = getName().length();
if (getNonLocalizedLabel() != null) {
@@ -117,6 +136,7 @@
dest.writeInt(this.protectionLevel);
dest.writeBoolean(this.tree);
dest.writeParcelable(this.parsedPermissionGroup, flags);
+ sForStringSet.parcel(knownCerts, dest, flags);
}
protected ParsedPermission(Parcel in) {
@@ -129,6 +149,7 @@
this.protectionLevel = in.readInt();
this.tree = in.readBoolean();
this.parsedPermissionGroup = in.readParcelable(boot);
+ this.knownCerts = sForStringSet.unparcel(in);
}
public static final Parcelable.Creator<ParsedPermission> CREATOR =
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index a7cecbe..8afa70e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -25,7 +25,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.R;
@@ -33,8 +32,6 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.util.Locale;
-import java.util.Set;
/** @hide */
public class ParsedPermissionUtils {
@@ -103,17 +100,12 @@
if (resourceType.equals("array")) {
final String[] knownCerts = res.getStringArray(knownCertsResource);
if (knownCerts != null) {
- // Convert the provided digest to upper case for consistent Set membership
- // checks when verifying the signing certificate digests of requesting apps.
- permission.knownCerts = new ArraySet<>();
- for (String knownCert : knownCerts) {
- permission.knownCerts.add(knownCert.toUpperCase(Locale.US));
- }
+ permission.setKnownCerts(knownCerts);
}
} else {
final String knownCert = res.getString(knownCertsResource);
if (knownCert != null) {
- permission.knownCerts = Set.of(knownCert.toUpperCase(Locale.US));
+ permission.setKnownCert(knownCert);
}
}
if (permission.knownCerts == null) {
@@ -126,7 +118,7 @@
final String knownCert = sa.getString(
R.styleable.AndroidManifestPermission_knownCerts);
if (knownCert != null) {
- permission.knownCerts = Set.of(knownCert.toUpperCase(Locale.US));
+ permission.setKnownCert(knownCert);
}
}
diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS
index cde7b2a..d302b0a 100644
--- a/core/java/android/content/pm/permission/OWNERS
+++ b/core/java/android/content/pm/permission/OWNERS
@@ -3,7 +3,6 @@
toddke@android.com
toddke@google.com
patb@google.com
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
zhanghai@google.com
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index 8f2b39d..8f5c2a0 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,4 +1,3 @@
# Bug component: 175220
-moltmann@google.com
badhri@google.com
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 6f89254..d631f68 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -5294,6 +5294,12 @@
pw.print(" flash=");
printmAh(pw, bs.flashlightPowerMah);
}
+ if (bs.customMeasuredPowerMah != null) {
+ for (int idx = 0; idx < bs.customMeasuredPowerMah.length; idx++) {
+ pw.print(" custom[" + idx + "]=");
+ printmAh(pw, bs.customMeasuredPowerMah[idx]);
+ }
+ }
pw.print(" )");
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 6a76da2..eac03dc 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1902,7 +1902,8 @@
* Retrieves the PSS memory used by the process as given by the smaps. Optionally supply a long
* array of up to 3 entries to also receive (up to 3 values in order): the Uss and SwapPss and
* Rss (only filled in as of {@link android.os.Build.VERSION_CODES#P}) of the process, and
- * another array to also retrieve the separate memtrack size.
+ * another array to also retrieve the separate memtrack sizes (up to 4 values in order): the
+ * total memtrack reported size, memtrack graphics, memtrack gl and memtrack other.
*
* @return The PSS memory usage, or 0 if failed to retrieve (i.e., given pid has gone).
* @hide
@@ -2589,6 +2590,13 @@
public static native long getIonPoolsSizeKb();
/**
+ * Return GPU DMA buffer usage in kB or -1 on error.
+ *
+ * @hide
+ */
+ public static native long getGpuDmaBufUsageKb();
+
+ /**
* Return DMA-BUF memory mapped by processes in kB.
* Notes:
* * Warning: Might impact performance as it reads /proc/<pid>/maps files for each process.
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 0ff68fc..0589994 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -241,6 +241,13 @@
}
/**
+ * Checks if device supports V2 calls (e.g. PerUid).
+ */
+ public static boolean isV2Available() {
+ return nativeIsV2Available();
+ }
+
+ /**
* Checks if Incremental installations are allowed.
* A developer can disable Incremental installations by setting the property.
*/
@@ -439,6 +446,7 @@
/* Native methods */
private static native boolean nativeIsEnabled();
+ private static native boolean nativeIsV2Available();
private static native boolean nativeIsIncrementalPath(@NonNull String path);
private static native byte[] nativeUnsafeGetFileSignature(@NonNull String path);
}
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index d09f351..b323468 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -1,6 +1,5 @@
# Bug component: 137825
-moltmann@google.com
evanseverson@google.com
ntmyren@google.com
zhanghai@google.com
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 85e9fdb..0e35ef9 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -693,13 +693,14 @@
for (int usageNum = 0; usageNum < rawUsages.size(); usageNum++) {
OpUsage usage = rawUsages.get(usageNum);
+ // If this attribution is a proxy, remove it
+ if (toRemoveProxies.contains(usage.toPackageAttr())) {
+ continue;
+ }
+
// If this attribution has a special attribution, do not remove it
if (specialAttributions.contains(usage.toPackageAttr())) {
deDuped.add(usage);
- }
-
- // If this attribution is a proxy, remove it
- if (toRemoveProxies.contains(usage.toPackageAttr())) {
continue;
}
diff --git a/core/java/android/permissionpresenterservice/OWNERS b/core/java/android/permissionpresenterservice/OWNERS
index d09f351..b323468 100644
--- a/core/java/android/permissionpresenterservice/OWNERS
+++ b/core/java/android/permissionpresenterservice/OWNERS
@@ -1,6 +1,5 @@
# Bug component: 137825
-moltmann@google.com
evanseverson@google.com
ntmyren@google.com
zhanghai@google.com
diff --git a/core/java/android/print/OWNERS b/core/java/android/print/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/print/OWNERS
+++ b/core/java/android/print/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/print/pdf/OWNERS b/core/java/android/print/pdf/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/print/pdf/OWNERS
+++ b/core/java/android/print/pdf/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/printservice/OWNERS b/core/java/android/printservice/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/printservice/OWNERS
+++ b/core/java/android/printservice/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/printservice/recommendation/OWNERS b/core/java/android/printservice/recommendation/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/printservice/recommendation/OWNERS
+++ b/core/java/android/printservice/recommendation/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/service/notification/NotificationListenerFilter.java b/core/java/android/service/notification/NotificationListenerFilter.java
index 6fdfaab..9de75ca 100644
--- a/core/java/android/service/notification/NotificationListenerFilter.java
+++ b/core/java/android/service/notification/NotificationListenerFilter.java
@@ -20,6 +20,7 @@
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
+import android.content.pm.VersionedPackage;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
@@ -31,7 +32,8 @@
*/
public class NotificationListenerFilter implements Parcelable {
private int mAllowedNotificationTypes;
- private ArraySet<String> mDisallowedPackages;
+ // VersionedPackage is holding the pkg name and pkg uid
+ private ArraySet<VersionedPackage> mDisallowedPackages;
public NotificationListenerFilter() {
mAllowedNotificationTypes = FLAG_FILTER_TYPE_CONVERSATIONS
@@ -41,7 +43,7 @@
mDisallowedPackages = new ArraySet<>();
}
- public NotificationListenerFilter(int types, ArraySet<String> pkgs) {
+ public NotificationListenerFilter(int types, ArraySet<VersionedPackage> pkgs) {
mAllowedNotificationTypes = types;
mDisallowedPackages = pkgs;
}
@@ -51,7 +53,8 @@
*/
protected NotificationListenerFilter(Parcel in) {
mAllowedNotificationTypes = in.readInt();
- mDisallowedPackages = (ArraySet<String>) in.readArraySet(String.class.getClassLoader());
+ mDisallowedPackages = (ArraySet<VersionedPackage>) in.readArraySet(
+ VersionedPackage.class.getClassLoader());
}
@Override
@@ -77,7 +80,7 @@
return (mAllowedNotificationTypes & type) != 0;
}
- public boolean isPackageAllowed(String pkg) {
+ public boolean isPackageAllowed(VersionedPackage pkg) {
return !mDisallowedPackages.contains(pkg);
}
@@ -85,7 +88,7 @@
return mAllowedNotificationTypes;
}
- public ArraySet<String> getDisallowedPackages() {
+ public ArraySet<VersionedPackage> getDisallowedPackages() {
return mDisallowedPackages;
}
@@ -93,10 +96,18 @@
mAllowedNotificationTypes = types;
}
- public void setDisallowedPackages(ArraySet<String> pkgs) {
+ public void setDisallowedPackages(ArraySet<VersionedPackage> pkgs) {
mDisallowedPackages = pkgs;
}
+ public void removePackage(VersionedPackage pkg) {
+ mDisallowedPackages.remove(pkg);
+ }
+
+ public void addPackage(VersionedPackage pkg) {
+ mDisallowedPackages.add(pkg);
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 64cddc3..f66f85b 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -80,6 +80,10 @@
* <intent-filter>
* <action android:name="android.service.notification.NotificationListenerService" />
* </intent-filter>
+ * <meta-data
+ * android:name="android.service.notification.default_filter_types"
+ * android:value="1,2">
+ * </meta-data>
* </service></pre>
*
* <p>The service should wait for the {@link #onListenerConnected()} event
@@ -103,6 +107,21 @@
private final String TAG = getClass().getSimpleName();
/**
+ * The name of the {@code meta-data} tag containing a comma separated list of default
+ * integer notification types that should be provided to this listener. See
+ * {@link #FLAG_FILTER_TYPE_ONGOING},
+ * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING),
+ * and {@link #FLAG_FILTER_TYPE_SILENT}.
+ * <p>This value will only be read if the app has not previously specified a default type list,
+ * and if the user has not overridden the allowed types.</p>
+ * <p>An absent value means 'allow all types'.
+ * A present but empty value means 'allow no types'.</p>
+ *
+ */
+ public static final String META_DATA_DEFAULT_FILTER_TYPES
+ = "android.service.notification.default_filter_types";
+
+ /**
* {@link #getCurrentInterruptionFilter() Interruption filter} constant -
* Normal interruption filter.
*/
@@ -254,23 +273,19 @@
/**
* A flag value indicating that this notification listener can see conversation type
* notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_CONVERSATIONS = 1;
/**
* A flag value indicating that this notification listener can see altering type notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_ALERTING = 2;
/**
* A flag value indicating that this notification listener can see silent type notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_SILENT = 4;
/**
* A flag value indicating that this notification listener can see important
* ( > {@link NotificationManager#IMPORTANCE_MIN}) ongoing type notifications.
- * @hide
*/
public static final int FLAG_FILTER_TYPE_ONGOING = 8;
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 6e9bc84..cba6af9 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -499,7 +499,7 @@
}
public String getPerfettoTrigger() {
- return String.format("interaction-jank-monitor-%d", mCujType);
+ return String.format("com.android.telemetry.interaction-jank-monitor-%d", mCujType);
}
public String getName() {
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index af61f91..9b88516 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -133,6 +133,7 @@
public double wakeLockPowerMah;
public double wifiPowerMah;
public double systemServiceCpuPowerMah;
+ public double[] customMeasuredPowerMah;
// Do not include this sipper in results because it is included
// in an aggregate sipper.
@@ -251,6 +252,17 @@
proportionalSmearMah += other.proportionalSmearMah;
totalSmearedPowerMah += other.totalSmearedPowerMah;
systemServiceCpuPowerMah += other.systemServiceCpuPowerMah;
+ if (other.customMeasuredPowerMah != null) {
+ if (customMeasuredPowerMah == null) {
+ customMeasuredPowerMah = new double[other.customMeasuredPowerMah.length];
+ }
+ if (customMeasuredPowerMah.length == other.customMeasuredPowerMah.length) {
+ // This should always be true.
+ for (int idx = 0; idx < other.customMeasuredPowerMah.length; idx++) {
+ customMeasuredPowerMah[idx] += other.customMeasuredPowerMah[idx];
+ }
+ }
+ }
}
/**
@@ -264,6 +276,11 @@
sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah
+ systemServiceCpuPowerMah;
+ if (customMeasuredPowerMah != null) {
+ for (int idx = 0; idx < customMeasuredPowerMah.length; idx++) {
+ totalPowerMah += customMeasuredPowerMah[idx];
+ }
+ }
totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah;
return totalPowerMah;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index aa5015a..b20f50d 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -347,6 +347,7 @@
mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
mPowerCalculators.add(new SystemServicePowerCalculator(mPowerProfile));
mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile));
+ mPowerCalculators.add(new CustomMeasuredPowerCalculator(mPowerProfile));
mPowerCalculators.add(new UserPowerCalculator());
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 96a71b9..a39d19e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -13002,16 +13002,17 @@
mWakeLockAllocationsUs = null;
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final List<Integer> uidsToRemove = new ArrayList<>();
mCpuUidFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
- mCpuUidFreqTimeReader.removeUid(uid);
+ uidsToRemove.add(uid);
if (DEBUG) Slog.d(TAG, "Got freq readings for an isolated uid: " + uid);
return;
}
if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
if (DEBUG) Slog.d(TAG, "Got freq readings for an invalid user's uid " + uid);
- mCpuUidFreqTimeReader.removeUid(uid);
+ uidsToRemove.add(uid);
return;
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
@@ -13070,6 +13071,9 @@
}
}
});
+ for (int uid : uidsToRemove) {
+ mCpuUidFreqTimeReader.removeUid(uid);
+ }
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
@@ -13116,21 +13120,25 @@
public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final List<Integer> uidsToRemove = new ArrayList<>();
mCpuUidActiveTimeReader.readDelta((uid, cpuActiveTimesMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
- mCpuUidActiveTimeReader.removeUid(uid);
+ uidsToRemove.add(uid);
if (DEBUG) Slog.w(TAG, "Got active times for an isolated uid: " + uid);
return;
}
if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
if (DEBUG) Slog.w(TAG, "Got active times for an invalid user's uid " + uid);
- mCpuUidActiveTimeReader.removeUid(uid);
+ uidsToRemove.add(uid);
return;
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesMs, onBattery);
});
+ for (int uid : uidsToRemove) {
+ mCpuUidActiveTimeReader.removeUid(uid);
+ }
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
@@ -13146,21 +13154,25 @@
public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final List<Integer> uidsToRemove = new ArrayList<>();
mCpuUidClusterTimeReader.readDelta((uid, cpuClusterTimesMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
- mCpuUidClusterTimeReader.removeUid(uid);
+ uidsToRemove.add(uid);
if (DEBUG) Slog.w(TAG, "Got cluster times for an isolated uid: " + uid);
return;
}
if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
if (DEBUG) Slog.w(TAG, "Got cluster times for an invalid user's uid " + uid);
- mCpuUidClusterTimeReader.removeUid(uid);
+ uidsToRemove.add(uid);
return;
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesMs, onBattery);
});
+ for (int uid : uidsToRemove) {
+ mCpuUidClusterTimeReader.removeUid(uid);
+ }
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 094724c..2798b72 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -72,6 +72,7 @@
mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
mPowerCalculators.add(new SystemServicePowerCalculator(mPowerProfile));
mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile));
+ mPowerCalculators.add(new CustomMeasuredPowerCalculator(mPowerProfile));
mPowerCalculators.add(new UserPowerCalculator());
}
diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
new file mode 100644
index 0000000..4babe8d
--- /dev/null
+++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+
+/**
+ * Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type
+ * {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
+ */
+public class CustomMeasuredPowerCalculator extends PowerCalculator {
+ public CustomMeasuredPowerCalculator(PowerProfile powerProfile) {
+ }
+
+ @Override
+ protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+ long rawUptimeUs, int statsType) {
+ updateCustomMeasuredPowerMah(app, u.getCustomMeasuredEnergiesMicroJoules());
+ }
+
+ private void updateCustomMeasuredPowerMah(BatterySipper sipper, long[] measuredEnergiesUJ) {
+ sipper.customMeasuredPowerMah = calculateMeasuredEnergiesMah(measuredEnergiesUJ);
+ }
+
+ private double[] calculateMeasuredEnergiesMah(long[] measuredEnergiesUJ) {
+ if (measuredEnergiesUJ == null) {
+ return null;
+ }
+ final double[] measuredEnergiesMah = new double[measuredEnergiesUJ.length];
+ for (int i = 0; i < measuredEnergiesUJ.length; i++) {
+ measuredEnergiesMah[i] = uJtoMah(measuredEnergiesUJ[i]);
+ }
+ return measuredEnergiesMah;
+ }
+}
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 488b18d..c6a040c 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -47,6 +47,13 @@
private CollectionUtils() { /* cannot be instantiated */ }
/**
+ * @see Collection#contains(Object)
+ */
+ public static <T> boolean contains(@Nullable Collection<T> collection, T element) {
+ return collection != null && collection.contains(element);
+ }
+
+ /**
* Returns a list of items from the provided list that match the given condition.
*
* This is similar to {@link Stream#filter} but without the overhead of creating an intermediate
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index f42f468..dc6880e 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -219,7 +219,7 @@
}
private static String getTraceTriggerNameForAction(@Action int action) {
- return "latency-tracker-" + getNameOfAction(STATSD_ACTION[action]);
+ return "com.android.telemetry.latency-tracker-" + getNameOfAction(STATSD_ACTION[action]);
}
public static boolean isEnabled(Context ctx) {
diff --git a/core/java/com/android/internal/util/PerfettoTrigger.java b/core/java/com/android/internal/util/PerfettoTrigger.java
index 9c87c69..c758504 100644
--- a/core/java/com/android/internal/util/PerfettoTrigger.java
+++ b/core/java/com/android/internal/util/PerfettoTrigger.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import android.os.SystemClock;
import android.util.Log;
import java.io.IOException;
@@ -27,16 +28,28 @@
public class PerfettoTrigger {
private static final String TAG = "PerfettoTrigger";
private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
+ private static final long THROTTLE_MILLIS = 60000;
+ private static volatile long sLastTriggerTime = -THROTTLE_MILLIS;
/**
* @param triggerName The name of the trigger. Must match the value defined in the AOT
* Perfetto config.
*/
public static void trigger(String triggerName) {
+ // Trace triggering has a non-negligible cost (fork+exec).
+ // To mitigate potential excessive triggering by the API client we ignore calls that happen
+ // too quickl after the most recent trigger.
+ long sinceLastTrigger = SystemClock.elapsedRealtime() - sLastTriggerTime;
+ if (sinceLastTrigger < THROTTLE_MILLIS) {
+ Log.v(TAG, "Not triggering " + triggerName + " - not enough time since last trigger");
+ return;
+ }
+
try {
ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, triggerName);
Log.v(TAG, "Triggering " + String.join(" ", pb.command()));
- Process process = pb.start();
+ pb.start();
+ sLastTriggerTime = SystemClock.elapsedRealtime();
} catch (IOException e) {
Log.w(TAG, "Failed to trigger " + triggerName, e);
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index cb586d6..8982519 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -1236,6 +1236,8 @@
if (IncrementalManager.isFeatureEnabled()) {
addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0);
+ addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY_VERSION,
+ IncrementalManager.isV2Available() ? 2 : 1);
}
if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 8edc8a1..9510f27 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -207,6 +207,7 @@
],
shared_libs: [
+ "android.hardware.memtrack-unstable-ndk_platform",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
"av-types-aidl-cpp",
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index c64174b..a7950f2 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,6 +33,7 @@
#include <string>
#include <vector>
+#include <aidl/android/hardware/memtrack/DeviceInfo.h>
#include <android-base/logging.h>
#include <bionic/malloc.h>
#include <debuggerd/client.h>
@@ -45,6 +46,7 @@
#include "jni.h"
#include <dmabufinfo/dmabuf_sysfs_stats.h>
#include <dmabufinfo/dmabufinfo.h>
+#include <dmabufinfo/dmabuf_sysfs_stats.h>
#include <meminfo/procmeminfo.h>
#include <meminfo/sysmeminfo.h>
#include <memtrack/memtrack.h>
@@ -520,14 +522,15 @@
}
if (outUssSwapPssRss != NULL) {
- if (env->GetArrayLength(outUssSwapPssRss) >= 1) {
+ int outLen = env->GetArrayLength(outUssSwapPssRss);
+ if (outLen >= 1) {
jlong* outUssSwapPssRssArray = env->GetLongArrayElements(outUssSwapPssRss, 0);
if (outUssSwapPssRssArray != NULL) {
outUssSwapPssRssArray[0] = uss;
- if (env->GetArrayLength(outUssSwapPssRss) >= 2) {
+ if (outLen >= 2) {
outUssSwapPssRssArray[1] = swapPss;
}
- if (env->GetArrayLength(outUssSwapPssRss) >= 3) {
+ if (outLen >= 3) {
outUssSwapPssRssArray[2] = rss;
}
}
@@ -536,10 +539,20 @@
}
if (outMemtrack != NULL) {
- if (env->GetArrayLength(outMemtrack) >= 1) {
+ int outLen = env->GetArrayLength(outMemtrack);
+ if (outLen >= 1) {
jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
if (outMemtrackArray != NULL) {
outMemtrackArray[0] = memtrack;
+ if (outLen >= 2) {
+ outMemtrackArray[1] = graphics_mem.graphics;
+ }
+ if (outLen >= 3) {
+ outMemtrackArray[2] = graphics_mem.gl;
+ }
+ if (outLen >= 4) {
+ outMemtrackArray[3] = graphics_mem.other;
+ }
}
env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
}
@@ -838,6 +851,31 @@
return poolsSizeKb;
}
+static jlong android_os_Debug_getGpuDmaBufUsageKb(JNIEnv* env, jobject clazz) {
+ std::vector<aidl::android::hardware::memtrack::DeviceInfo> gpu_device_info;
+ if (!memtrack_gpu_device_info(&gpu_device_info)) {
+ return -1;
+ }
+
+ dmabufinfo::DmabufSysfsStats stats;
+ if (!GetDmabufSysfsStats(&stats)) {
+ return -1;
+ }
+
+ jlong sizeKb = 0;
+ const auto& importer_stats = stats.importer_info();
+ for (const auto& dev_info : gpu_device_info) {
+ const auto& importer_info = importer_stats.find(dev_info.name);
+ if (importer_info == importer_stats.end()) {
+ continue;
+ }
+
+ sizeKb += importer_info->second.size;
+ }
+
+ return sizeKb;
+}
+
static jlong android_os_Debug_getDmabufMappedSizeKb(JNIEnv* env, jobject clazz) {
jlong dmabufPss = 0;
std::vector<dmabufinfo::DmaBuffer> dmabufs;
@@ -946,6 +984,8 @@
(void*)android_os_Debug_getIonHeapsSizeKb },
{ "getDmabufTotalExportedKb", "()J",
(void*)android_os_Debug_getDmabufTotalExportedKb },
+ { "getGpuDmaBufUsageKb", "()J",
+ (void*)android_os_Debug_getGpuDmaBufUsageKb },
{ "getIonPoolsSizeKb", "()J",
(void*)android_os_Debug_getIonPoolsSizeKb },
{ "getDmabufMappedSizeKb", "()J",
diff --git a/core/jni/android_os_incremental_IncrementalManager.cpp b/core/jni/android_os_incremental_IncrementalManager.cpp
index 44bff01..2384efa 100644
--- a/core/jni/android_os_incremental_IncrementalManager.cpp
+++ b/core/jni/android_os_incremental_IncrementalManager.cpp
@@ -30,6 +30,10 @@
return IncFs_IsEnabled();
}
+static jboolean nativeIsV2Available(JNIEnv* env, jobject clazz) {
+ return !!(IncFs_Features() & INCFS_FEATURE_V2);
+}
+
static jboolean nativeIsIncrementalPath(JNIEnv* env,
jobject clazz,
jstring javaPath) {
@@ -53,12 +57,12 @@
return result;
}
-static const JNINativeMethod method_table[] = {{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
- {"nativeIsIncrementalPath", "(Ljava/lang/String;)Z",
- (void*)nativeIsIncrementalPath},
- {"nativeUnsafeGetFileSignature",
- "(Ljava/lang/String;)[B",
- (void*)nativeUnsafeGetFileSignature}};
+static const JNINativeMethod method_table[] =
+ {{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
+ {"nativeIsV2Available", "()Z", (void*)nativeIsV2Available},
+ {"nativeIsIncrementalPath", "(Ljava/lang/String;)Z", (void*)nativeIsIncrementalPath},
+ {"nativeUnsafeGetFileSignature", "(Ljava/lang/String;)[B",
+ (void*)nativeUnsafeGetFileSignature}};
int register_android_os_incremental_IncrementalManager(JNIEnv* env) {
return jniRegisterNativeMethods(env, "android/os/incremental/IncrementalManager",
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 09ca12a..b7c755e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1590,8 +1590,8 @@
take precedence over lower ones.
See com.android.server.timedetector.TimeDetectorStrategy for available sources. -->
<string-array name="config_autoTimeSourcesPriority">
- <item>telephony</item>
<item>network</item>
+ <item>telephony</item>
</string-array>
<!-- Enables the GnssTimeUpdate service. This is the global switch for enabling Gnss time based
diff --git a/core/tests/coretests/src/android/content/pm/PermissionInfoTest.java b/core/tests/coretests/src/android/content/pm/PermissionInfoTest.java
new file mode 100644
index 0000000..606e81d
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/PermissionInfoTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.util.ArraySet;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class PermissionInfoTest {
+ private static final String KNOWN_CERT_DIGEST_1 =
+ "6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599";
+ private static final String KNOWN_CERT_DIGEST_2 =
+ "9369370ffcfdc1e92dae777252c05c483b8cbb55fa9d5fd9f6317f623ae6d8c6";
+
+ @Test
+ public void createFromParcel_returnsKnownCerts() {
+ // The platform supports a knownSigner permission protection flag that allows one or more
+ // trusted signing certificates to be specified with the permission declaration; if a
+ // requesting app is signed by any of these trusted certificates the permission is granted.
+ // This test verifies the Set of knownCerts is properly parceled / unparceled.
+ PermissionInfo permissionInfo = new PermissionInfo();
+ permissionInfo.protectionLevel =
+ PermissionInfo.PROTECTION_SIGNATURE | PermissionInfo.PROTECTION_FLAG_KNOWN_SIGNER;
+ permissionInfo.knownCerts = new ArraySet<>(2);
+ permissionInfo.knownCerts.add(KNOWN_CERT_DIGEST_1);
+ permissionInfo.knownCerts.add(KNOWN_CERT_DIGEST_2);
+ Parcel parcel = Parcel.obtain();
+ permissionInfo.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+ PermissionInfo unparceledPermissionInfo = PermissionInfo.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(unparceledPermissionInfo.knownCerts);
+ assertEquals(2, unparceledPermissionInfo.knownCerts.size());
+ assertTrue(unparceledPermissionInfo.knownCerts.contains(KNOWN_CERT_DIGEST_1));
+ assertTrue(unparceledPermissionInfo.knownCerts.contains(KNOWN_CERT_DIGEST_2));
+ }
+}
diff --git a/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java b/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java
index a43b238..a121941 100644
--- a/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java
+++ b/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java
@@ -16,14 +16,14 @@
package android.service.notification;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static com.google.common.truth.Truth.assertThat;
-import android.app.NotificationChannel;
+import android.content.pm.VersionedPackage;
import android.os.Parcel;
import android.util.ArraySet;
@@ -45,16 +45,19 @@
assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isTrue();
assertThat(nlf.getTypes()).isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS
| FLAG_FILTER_TYPE_ALERTING
- | FLAG_FILTER_TYPE_SILENT);
+ | FLAG_FILTER_TYPE_SILENT
+ | FLAG_FILTER_TYPE_ONGOING);
assertThat(nlf.getDisallowedPackages()).isEmpty();
- assertThat(nlf.isPackageAllowed("pkg1")).isTrue();
+ assertThat(nlf.isPackageAllowed(new VersionedPackage("any", 0))).isTrue();
}
@Test
public void testConstructor() {
- ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"});
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
+ VersionedPackage a2= new VersionedPackage("pkg2", 2142534);
+ ArraySet<VersionedPackage> pkgs = new ArraySet<>(new VersionedPackage[] {a1, a2});
NotificationListenerFilter nlf =
new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs);
assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_CONVERSATIONS)).isFalse();
@@ -62,20 +65,21 @@
assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isFalse();
assertThat(nlf.getTypes()).isEqualTo(FLAG_FILTER_TYPE_ALERTING);
- assertThat(nlf.getDisallowedPackages()).contains("pkg1");
- assertThat(nlf.getDisallowedPackages()).contains("pkg2");
- assertThat(nlf.isPackageAllowed("pkg1")).isFalse();
- assertThat(nlf.isPackageAllowed("pkg2")).isFalse();
+ assertThat(nlf.getDisallowedPackages()).contains(a1);
+ assertThat(nlf.getDisallowedPackages()).contains(a2);
+ assertThat(nlf.isPackageAllowed(a1)).isFalse();
+ assertThat(nlf.isPackageAllowed(a2)).isFalse();
}
@Test
public void testSetDisallowedPackages() {
NotificationListenerFilter nlf = new NotificationListenerFilter();
- ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1"});
+ ArraySet<VersionedPackage> pkgs = new ArraySet<>(
+ new VersionedPackage[] {new VersionedPackage("pkg1", 0)});
nlf.setDisallowedPackages(pkgs);
- assertThat(nlf.isPackageAllowed("pkg1")).isFalse();
+ assertThat(nlf.isPackageAllowed(new VersionedPackage("pkg1", 0))).isFalse();
}
@Test
@@ -94,7 +98,9 @@
@Test
public void testDescribeContents() {
final int expected = 0;
- ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"});
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
+ VersionedPackage a2= new VersionedPackage("pkg2", 2142534);
+ ArraySet<VersionedPackage> pkgs = new ArraySet<>(new VersionedPackage[] {a1, a2});
NotificationListenerFilter nlf =
new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs);
assertThat(nlf.describeContents()).isEqualTo(expected);
@@ -102,7 +108,9 @@
@Test
public void testParceling() {
- ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"});
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
+ VersionedPackage a2= new VersionedPackage("pkg2", 2142534);
+ ArraySet<VersionedPackage> pkgs = new ArraySet<>(new VersionedPackage[] {a1, a2});
NotificationListenerFilter nlf =
new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs);
@@ -116,9 +124,9 @@
assertThat(nlf1.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isFalse();
assertThat(nlf1.getTypes()).isEqualTo(FLAG_FILTER_TYPE_ALERTING);
- assertThat(nlf1.getDisallowedPackages()).contains("pkg1");
- assertThat(nlf1.getDisallowedPackages()).contains("pkg2");
- assertThat(nlf1.isPackageAllowed("pkg1")).isFalse();
- assertThat(nlf1.isPackageAllowed("pkg2")).isFalse();
+ assertThat(nlf1.getDisallowedPackages()).contains(a1);
+ assertThat(nlf1.getDisallowedPackages()).contains(a2);
+ assertThat(nlf1.isPackageAllowed(a1)).isFalse();
+ assertThat(nlf1.isPackageAllowed(a2)).isFalse();
}
}
diff --git a/core/tests/coretests/src/com/android/internal/widget/OWNERS b/core/tests/coretests/src/com/android/internal/widget/OWNERS
new file mode 100644
index 0000000..b40fe24
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/OWNERS
@@ -0,0 +1,3 @@
+# LockSettings related
+per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 65d3a01..549e074 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -6,7 +6,6 @@
jsharkey@android.com
jsharkey@google.com
lorenzo@google.com
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
toddke@android.com
diff --git a/data/etc/car/com.android.car.provision.xml b/data/etc/car/com.android.car.provision.xml
index 4fd9cae..42cfd3c 100644
--- a/data/etc/car/com.android.car.provision.xml
+++ b/data/etc/car/com.android.car.provision.xml
@@ -17,6 +17,7 @@
<permissions>
<privapp-permissions package="com.android.car.provision">
<permission name="android.car.permission.CAR_POWERTRAIN"/>
+ <permission name="android.permission.DISPATCH_PROVISIONING_MESSAGE"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<permission name="android.permission.MANAGE_USERS"/>
diff --git a/data/etc/com.android.emergency.xml b/data/etc/com.android.emergency.xml
index 734561c..fa92b6d 100644
--- a/data/etc/com.android.emergency.xml
+++ b/data/etc/com.android.emergency.xml
@@ -19,6 +19,7 @@
<!-- Required to place emergency calls from emergency info screen. -->
<permission name="android.permission.CALL_PRIVILEGED"/>
<permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/com.android.provision.xml b/data/etc/com.android.provision.xml
index d2ea0ec..68f8298 100644
--- a/data/etc/com.android.provision.xml
+++ b/data/etc/com.android.provision.xml
@@ -17,7 +17,7 @@
<permissions>
<privapp-permissions package="com.android.provision">
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
- <permissionn ame="android.permission.DISPATCH_PROVISIONING_MESSAGE"/>
+ <permission name="android.permission.DISPATCH_PROVISIONING_MESSAGE"/>
<permission name="android.permission.MASTER_CLEAR"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index e473c55..3fdb0da 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -58,5 +58,6 @@
<permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
<permission name="android.permission.READ_DREAM_STATE"/>
<permission name="android.permission.READ_DREAM_SUPPRESSION"/>
+ <permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
</privapp-permissions>
</permissions>
diff --git a/graphics/java/android/graphics/pdf/OWNERS b/graphics/java/android/graphics/pdf/OWNERS
index f04e200..057dc0d 100644
--- a/graphics/java/android/graphics/pdf/OWNERS
+++ b/graphics/java/android/graphics/pdf/OWNERS
@@ -5,4 +5,3 @@
sumir@google.com
svetoslavganov@android.com
svetoslavganov@google.com
-moltmann@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 2391a08..047df5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -86,6 +86,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -586,11 +587,15 @@
// There were no bubbles saved for this used.
return;
}
- for (BubbleEntry e : mSysuiProxy.getShouldRestoredEntries(savedBubbleKeys)) {
- if (canLaunchInActivityView(mContext, e)) {
- updateBubble(e, true /* suppressFlyout */, false /* showInShade */);
- }
- }
+ mSysuiProxy.getShouldRestoredEntries(savedBubbleKeys, (entries) -> {
+ mMainExecutor.execute(() -> {
+ for (BubbleEntry e : entries) {
+ if (canLaunchInActivityView(mContext, e)) {
+ updateBubble(e, true /* suppressFlyout */, false /* showInShade */);
+ }
+ }
+ });
+ });
// Finally, remove the entries for this user now that bubbles are restored.
mSavedBubbleKeysPerUser.remove(mCurrentUserId);
}
@@ -856,21 +861,24 @@
}
}
- private void onRankingUpdated(RankingMap rankingMap) {
+ private void onRankingUpdated(RankingMap rankingMap,
+ HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey) {
if (mTmpRanking == null) {
mTmpRanking = new NotificationListenerService.Ranking();
}
String[] orderedKeys = rankingMap.getOrderedKeys();
for (int i = 0; i < orderedKeys.length; i++) {
String key = orderedKeys[i];
- BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(key);
+ Pair<BubbleEntry, Boolean> entryData = entryDataByKey.get(key);
+ BubbleEntry entry = entryData.first;
+ boolean shouldBubbleUp = entryData.second;
rankingMap.getRanking(key, mTmpRanking);
boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
if (isActiveBubble && !mTmpRanking.canBubble()) {
// If this entry is no longer allowed to bubble, dismiss with the BLOCKED reason.
// This means that the app or channel's ability to bubble has been revoked.
mBubbleData.dismissBubbleWithKey(key, DISMISS_BLOCKED);
- } else if (isActiveBubble && !mSysuiProxy.shouldBubbleUp(key)) {
+ } else if (isActiveBubble && !shouldBubbleUp) {
// If this entry is allowed to bubble, but cannot currently bubble up, dismiss it.
// This happens when DND is enabled and configured to hide bubbles. Dismissing with
// the reason DISMISS_NO_BUBBLE_UP will retain the underlying notification, so that
@@ -919,17 +927,20 @@
private void setIsBubble(@NonNull final Bubble b, final boolean isBubble) {
Objects.requireNonNull(b);
b.setIsBubble(isBubble);
- final BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(b.getKey());
- if (entry != null) {
- // Updating the entry to be a bubble will trigger our normal update flow
- setIsBubble(entry, isBubble, b.shouldAutoExpand());
- } else if (isBubble) {
- // If bubble doesn't exist, it's a persisted bubble so we need to add it to the
- // stack ourselves
- Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */);
- inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */,
- !bubble.shouldAutoExpand() /* showInShade */);
- }
+ mSysuiProxy.getPendingOrActiveEntry(b.getKey(), (entry) -> {
+ mMainExecutor.execute(() -> {
+ if (entry != null) {
+ // Updating the entry to be a bubble will trigger our normal update flow
+ setIsBubble(entry, isBubble, b.shouldAutoExpand());
+ } else if (isBubble) {
+ // If bubble doesn't exist, it's a persisted bubble so we need to add it to the
+ // stack ourselves
+ Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */);
+ inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */,
+ !bubble.shouldAutoExpand() /* showInShade */);
+ }
+ });
+ });
}
@SuppressWarnings("FieldCanBeLocal")
@@ -992,14 +1003,17 @@
}
}
- final BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(bubble.getKey());
- if (entry != null) {
- final String groupKey = entry.getStatusBarNotification().getGroupKey();
- if (getBubblesInGroup(groupKey).isEmpty()) {
- // Time to potentially remove the summary
- mSysuiProxy.notifyMaybeCancelSummary(bubble.getKey());
- }
- }
+ mSysuiProxy.getPendingOrActiveEntry(bubble.getKey(), (entry) -> {
+ mMainExecutor.execute(() -> {
+ if (entry != null) {
+ final String groupKey = entry.getStatusBarNotification().getGroupKey();
+ if (getBubblesInGroup(groupKey).isEmpty()) {
+ // Time to potentially remove the summary
+ mSysuiProxy.notifyMaybeCancelSummary(bubble.getKey());
+ }
+ }
+ });
+ });
}
mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
@@ -1121,23 +1135,6 @@
mStackView.updateContentDescription();
}
- /**
- * The task id of the expanded view, if the stack is expanded and not occluded by the
- * status bar, otherwise returns {@link ActivityTaskManager#INVALID_TASK_ID}.
- */
- private int getExpandedTaskId() {
- if (mStackView == null) {
- return INVALID_TASK_ID;
- }
- final BubbleViewProvider expandedViewProvider = mStackView.getExpandedBubble();
- if (expandedViewProvider != null && isStackExpanded()
- && !mStackView.isExpansionAnimating()
- && !mSysuiProxy.isNotificationShadeExpand()) {
- return expandedViewProvider.getTaskId();
- }
- return INVALID_TASK_ID;
- }
-
@VisibleForTesting
public BubbleStackView getStackView() {
return mStackView;
@@ -1343,9 +1340,10 @@
}
@Override
- public void onRankingUpdated(RankingMap rankingMap) {
+ public void onRankingUpdated(RankingMap rankingMap,
+ HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey) {
mMainExecutor.execute(() -> {
- BubbleController.this.onRankingUpdated(rankingMap);
+ BubbleController.this.onRankingUpdated(rankingMap, entryDataByKey);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 6a1026b..8e061e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -26,6 +26,7 @@
import android.os.Looper;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
+import android.util.Pair;
import android.view.View;
import androidx.annotation.IntDef;
@@ -37,6 +38,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
+import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
@@ -182,8 +184,11 @@
* permissions on the notification channel or the global setting.
*
* @param rankingMap the updated ranking map from NotificationListenerService
+ * @param entryDataByKey a map of ranking key to bubble entry and whether the entry should
+ * bubble up
*/
- void onRankingUpdated(RankingMap rankingMap);
+ void onRankingUpdated(RankingMap rankingMap,
+ HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey);
/**
* Called when the status bar has become visible or invisible (either permanently or
@@ -243,14 +248,10 @@
/** Callback to tell SysUi components execute some methods. */
interface SysuiProxy {
- @Nullable
- BubbleEntry getPendingOrActiveEntry(String key);
+ void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback);
- List<BubbleEntry> getShouldRestoredEntries(ArraySet<String> savedBubbleKeys);
-
- boolean isNotificationShadeExpand();
-
- boolean shouldBubbleUp(String key);
+ void getShouldRestoredEntries(ArraySet<String> savedBubbleKeys,
+ Consumer<List<BubbleEntry>> callback);
void setNotificationInterruption(String key);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
index 94c6f01..c8f8987 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
@@ -39,7 +39,6 @@
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
import com.android.internal.annotations.GuardedBy;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -116,7 +115,7 @@
void applyResizeSplits(int position, LegacySplitDisplayLayout splitLayout) {
WindowContainerTransaction t = new WindowContainerTransaction();
splitLayout.resizeSplits(position, t);
- new WindowOrganizer().applyTransaction(t);
+ applySyncTransaction(t);
}
boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index a6f44ef..b7fd3cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -43,6 +43,7 @@
import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.getNavigationBarRect;
+import android.annotation.BinderThread;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
@@ -498,7 +499,7 @@
}
}
- @ExternalThread
+ @BinderThread
static class Window extends BaseIWindow {
private TaskSnapshotWindow mOuter;
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 1dc5cd9..2e4d7f62 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -239,14 +239,12 @@
static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
ScopedUtfChars strSksl(env, sksl);
- auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()));
- sk_sp<SkRuntimeEffect> effect = std::get<0>(result);
- if (effect.get() == nullptr) {
- const auto& err = std::get<1>(result);
- doThrowIAE(env, err.c_str());
+ auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()), SkRuntimeEffect::Options{});
+ if (result.effect.get() == nullptr) {
+ doThrowIAE(env, result.errorText.c_str());
return 0;
}
- return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(effect)));
+ return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
}
static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index cf2f0f0..a7ed091 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -10,7 +10,7 @@
"include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
},
{
- "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
+ "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
}
]
}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 314bf29..7a18bd5 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -225,6 +225,7 @@
AStorageManager_unmountObb;
ASurfaceControl_create; # introduced=29
ASurfaceControl_createFromWindow; # introduced=29
+ ASurfaceControl_acquire; # introduced=31
ASurfaceControl_release; # introduced=29
ASurfaceTexture_acquireANativeWindow; # introduced=28
ASurfaceTexture_attachToGLContext; # introduced=28
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 189be80..c1b5f1d 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -185,10 +185,16 @@
return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
}
-void ASurfaceControl_release(ASurfaceControl* aSurfaceControl) {
- sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+void ASurfaceControl_acquire(ASurfaceControl* aSurfaceControl) {
+ SurfaceControl* surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
- SurfaceControl_release(surfaceControl.get());
+ SurfaceControl_acquire(surfaceControl);
+}
+
+void ASurfaceControl_release(ASurfaceControl* aSurfaceControl) {
+ SurfaceControl* surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+
+ SurfaceControl_release(surfaceControl);
}
ASurfaceTransaction* ASurfaceTransaction_create() {
diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS
index 252670a..8e1774b 100644
--- a/packages/PackageInstaller/OWNERS
+++ b/packages/PackageInstaller/OWNERS
@@ -1,5 +1,4 @@
svetoslavganov@google.com
-moltmann@google.com
toddke@google.com
suprabh@google.com
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_1.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_1.xml
new file mode 100644
index 0000000..46e2d45
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_1.xml
@@ -0,0 +1,35 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M13,8h2v3h-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.5,5h2v6h-2z"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,3h2v8h-2z"
+ android:fillAlpha="0.3"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_2.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_2.xml
new file mode 100644
index 0000000..d9cd590
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_2.xml
@@ -0,0 +1,34 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M13,8h2v3h-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.5,5h2v6h-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,3h2v8h-2z"
+ android:fillAlpha="0.3"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_3.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_3.xml
new file mode 100644
index 0000000..e80fd08
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_3.xml
@@ -0,0 +1,33 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M13,8h2v3h-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.5,5h2v6h-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,3h2v8h-2z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_1.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_1.xml
new file mode 100644
index 0000000..493912b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_1.xml
@@ -0,0 +1,35 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18.05,9.59C17.69,9.22 17.19,9 16.64,9c-0.55,0 -1.05,0.22 -1.41,0.59L16.64,11L18.05,9.59z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.64,7.5c0.96,0 1.84,0.39 2.47,1.03l1.42,-1.42c-1,-1 -2.37,-1.61 -3.89,-1.61c-1.52,0 -2.89,0.62 -3.89,1.61l1.42,1.42C14.8,7.89 15.67,7.5 16.64,7.5z"
+ android:fillAlpha="0.3"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.64,4c1.93,0 3.68,0.79 4.95,2.05L23,4.64C21.37,3.01 19.12,2 16.64,2c-2.49,0 -4.74,1.01 -6.36,2.64l1.42,1.42C12.96,4.79 14.71,4 16.64,4z"
+ android:fillAlpha="0.3"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_2.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_2.xml
new file mode 100644
index 0000000..af677fb
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_2.xml
@@ -0,0 +1,34 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18.05,9.59C17.69,9.22 17.19,9 16.64,9c-0.55,0 -1.05,0.22 -1.41,0.59L16.64,11L18.05,9.59z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.64,7.5c0.96,0 1.84,0.39 2.47,1.03l1.42,-1.42c-1,-1 -2.37,-1.61 -3.89,-1.61c-1.52,0 -2.89,0.62 -3.89,1.61l1.42,1.42C14.8,7.89 15.67,7.5 16.64,7.5z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.64,4c1.93,0 3.68,0.79 4.95,2.05L23,4.64C21.37,3.01 19.12,2 16.64,2c-2.49,0 -4.74,1.01 -6.36,2.64l1.42,1.42C12.96,4.79 14.71,4 16.64,4z"
+ android:fillAlpha="0.3"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_3.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_3.xml
new file mode 100644
index 0000000..68b39da
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_3.xml
@@ -0,0 +1,33 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18.05,9.59C17.69,9.22 17.19,9 16.64,9c-0.55,0 -1.05,0.22 -1.41,0.59L16.64,11L18.05,9.59z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.64,7.5c0.96,0 1.84,0.39 2.47,1.03l1.42,-1.42c-1,-1 -2.37,-1.61 -3.89,-1.61c-1.52,0 -2.89,0.62 -3.89,1.61l1.42,1.42C14.8,7.89 15.67,7.5 16.64,7.5z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.64,4c1.93,0 3.68,0.79 4.95,2.05L23,4.64C21.37,3.01 19.12,2 16.64,2c-2.49,0 -4.74,1.01 -6.36,2.64l1.42,1.42C12.96,4.79 14.71,4 16.64,4z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7556ace..3866151 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1380,7 +1380,7 @@
<!-- Label for adding a new guest in the user switcher [CHAR LIMIT=35] -->
<string name="guest_new_guest">Add guest</string>
<!-- Label for exiting and removing the guest session in the user switcher [CHAR LIMIT=35] -->
- <string name="guest_exit_guest">End guest session</string>
+ <string name="guest_exit_guest">Remove guest</string>
<!-- Name for the guest user [CHAR LIMIT=35] -->
<string name="guest_nickname">Guest</string>
@@ -1485,4 +1485,7 @@
<string name="accessibility_ethernet_disconnected">Ethernet disconnected.</string>
<!-- Content description of the Ethernet connection when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_ethernet_connected">Ethernet.</string>
+
+ <!-- Content description of the no calling for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_no_calling">No calling.</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
index 45028ff..eff9e74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
@@ -48,6 +48,8 @@
public static final int WIFI_NO_CONNECTION = R.string.accessibility_no_wifi;
+ public static final int NO_CALLING = R.string.accessibility_no_calling;
+
public static final int[] ETHERNET_CONNECTION_VALUES = {
R.string.accessibility_ethernet_disconnected,
R.string.accessibility_ethernet_connected,
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
index 4c7b898..0cd5e4d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
@@ -266,7 +266,7 @@
serviceState.getDataRegState()) + ")")
.append(',')
.append("signalStrength=").append(signalStrength == null ? ""
- : signalStrength.toString()).append(',')
+ : signalStrength.getLevel()).append(',')
.append("telephonyDisplayInfo=").append(telephonyDisplayInfo == null ? ""
: telephonyDisplayInfo.toString()).append(']').toString();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
index 0cb9906..e3413aa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
@@ -317,5 +317,21 @@
ICON_NAME_TO_ICON.put("datadisable", DATA_DISABLED);
ICON_NAME_TO_ICON.put("notdefaultdata", NOT_DEFAULT_DATA);
}
+
+ public static final int[] WIFI_CALL_STRENGTH_ICONS = {
+ R.drawable.ic_wifi_call_strength_1,
+ R.drawable.ic_wifi_call_strength_1,
+ R.drawable.ic_wifi_call_strength_2,
+ R.drawable.ic_wifi_call_strength_3,
+ R.drawable.ic_wifi_call_strength_3
+ };
+
+ public static final int[] MOBILE_CALL_STRENGTH_ICONS = {
+ R.drawable.ic_mobile_call_strength_1,
+ R.drawable.ic_mobile_call_strength_1,
+ R.drawable.ic_mobile_call_strength_2,
+ R.drawable.ic_mobile_call_strength_3,
+ R.drawable.ic_mobile_call_strength_3
+ };
}
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 6ba1fcb..34901f5 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -6,7 +6,6 @@
svetoslavganov@google.com
hackbod@google.com
yamasani@google.com
-moltmann@google.com
toddke@google.com
cbrubaker@google.com
omakoto@google.com
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 8166e35..a1191ae 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -139,6 +139,10 @@
<!-- Size of shadows/elevations on keyguard -->
<attr name="shadowRadius" format="float" />
+ <attr name="handleThickness" format="dimension" />
+ <attr name="handleColor" format="color" />
+ <attr name="scrimColor" format="color" />
+
<!-- Used display CarrierText in Keyguard or QS Footer -->
<declare-styleable name="CarrierText">
<attr name="allCaps" format="boolean" />
@@ -173,15 +177,15 @@
</declare-styleable>
<declare-styleable name="CropView">
- <attr name="handleThickness" format="dimension" />
- <attr name="handleColor" format="color" />
- <attr name="scrimColor" format="color" />
+ <attr name="handleThickness" />
+ <attr name="handleColor" />
+ <attr name="scrimColor" />
</declare-styleable>
<declare-styleable name="MagnifierView">
- <attr name="handleThickness" format="dimension" />
- <attr name="handleColor" format="color" />
- <attr name="scrimColor" format="color" />
+ <attr name="handleThickness" />
+ <attr name="handleColor" />
+ <attr name="scrimColor" />
<attr name="borderThickness" format="dimension" />
<attr name="borderColor" format="color" />
</declare-styleable>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index f83965e..6d731f8 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -18,7 +18,7 @@
<resources>
<bool name="are_flags_overrideable">false</bool>
- <bool name="flag_notification_pipeline2">false</bool>
+ <bool name="flag_notification_pipeline2">true</bool>
<bool name="flag_notification_pipeline2_rendering">false</bool>
<bool name="flag_notif_updates">false</bool>
@@ -35,9 +35,6 @@
<bool name="flag_brightness_slider">false</bool>
- <!-- The new animations to/from lockscreen and AOD! -->
- <bool name="flag_lockscreen_animations">false</bool>
-
<!-- People Tile flag -->
<bool name="flag_conversations">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7c1c24b..d997ca2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1116,13 +1116,13 @@
<string name="guest_exit_button">End guest session</string>
<!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
- <string name="guest_exit_guest_dialog_title">End guest session?</string>
+ <string name="guest_exit_guest_dialog_title">Remove guest?</string>
<!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
<string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string>
<!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
- <string name="guest_exit_guest_dialog_remove">End session</string>
+ <string name="guest_exit_guest_dialog_remove">Remove</string>
<!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] -->
<string name="guest_wipe_session_title">Welcome back, guest!</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index eddcf8c..ae0b5d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
@@ -39,6 +39,7 @@
private ImageView mMobileSignal;
private ImageView mMobileRoaming;
private CellSignalState mLastSignalState;
+ private boolean mProviderModel;
public QSCarrier(Context context) {
super(context);
@@ -59,15 +60,20 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mMobileGroup = findViewById(R.id.mobile_combo);
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
- mMobileRoaming = findViewById(R.id.mobile_roaming_large);
+ mProviderModel = true;
} else {
- mMobileRoaming = findViewById(R.id.mobile_roaming);
+ mProviderModel = false;
}
+ mMobileGroup = findViewById(R.id.mobile_combo);
+ mMobileRoaming = findViewById(R.id.mobile_roaming);
mMobileSignal = findViewById(R.id.mobile_signal);
mCarrierText = findViewById(R.id.qs_carrier_text);
- mMobileSignal.setImageDrawable(new SignalDrawable(mContext));
+ if (mProviderModel) {
+ mMobileSignal.setImageDrawable(mContext.getDrawable(R.drawable.ic_qs_no_calling_sms));
+ } else {
+ mMobileSignal.setImageDrawable(new SignalDrawable(mContext));
+ }
}
/**
@@ -85,22 +91,27 @@
android.R.attr.textColorPrimary);
mMobileRoaming.setImageTintList(colorStateList);
mMobileSignal.setImageTintList(colorStateList);
- mMobileSignal.setImageLevel(state.mobileSignalIconId);
- StringBuilder contentDescription = new StringBuilder();
- if (state.contentDescription != null) {
- contentDescription.append(state.contentDescription).append(", ");
+ if (mProviderModel) {
+ mMobileSignal.setImageDrawable(mContext.getDrawable(state.mobileSignalIconId));
+ mMobileSignal.setContentDescription(state.contentDescription);
+ } else {
+ mMobileSignal.setImageLevel(state.mobileSignalIconId);
+ StringBuilder contentDescription = new StringBuilder();
+ if (state.contentDescription != null) {
+ contentDescription.append(state.contentDescription).append(", ");
+ }
+ if (state.roaming) {
+ contentDescription
+ .append(mContext.getString(R.string.data_connection_roaming))
+ .append(", ");
+ }
+ // TODO: show mobile data off/no internet text for 5 seconds before carrier text
+ if (hasValidTypeContentDescription(state.typeContentDescription)) {
+ contentDescription.append(state.typeContentDescription);
+ }
+ mMobileSignal.setContentDescription(contentDescription);
}
- if (state.roaming) {
- contentDescription
- .append(mContext.getString(R.string.data_connection_roaming))
- .append(", ");
- }
- // TODO: show mobile data off/no internet text for 5 seconds before carrier text
- if (hasValidTypeContentDescription(state.typeContentDescription)) {
- contentDescription.append(state.typeContentDescription);
- }
- mMobileSignal.setContentDescription(contentDescription);
}
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index 77200cc..a567f51 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -19,6 +19,7 @@
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import android.annotation.MainThread;
+import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
@@ -26,6 +27,7 @@
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
@@ -33,6 +35,9 @@
import androidx.annotation.VisibleForTesting;
import com.android.keyguard.CarrierTextController;
+import com.android.settingslib.AccessibilityContentDescriptions;
+import com.android.settingslib.mobile.TelephonyIcons;
+import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -62,6 +67,9 @@
new CellSignalState[SIM_SLOTS];
private View[] mCarrierDividers = new View[SIM_SLOTS - 1];
private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
+ private int[] mLastSignalLevel = new int[SIM_SLOTS];
+ private String[] mLastSignalLevelDescription = new String[SIM_SLOTS];
+ private final boolean mProviderModel;
private final NetworkController.SignalCallback mSignalCallback =
new NetworkController.SignalCallback() {
@@ -72,6 +80,9 @@
CharSequence typeContentDescription,
CharSequence typeContentDescriptionHtml, CharSequence description,
boolean isWide, int subId, boolean roaming, boolean showTriangle) {
+ if (mProviderModel) {
+ return;
+ }
int slotIndex = getSlotIndex(subId);
if (slotIndex >= SIM_SLOTS) {
Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
@@ -92,6 +103,46 @@
}
@Override
+ public void setCallIndicator(NetworkController.IconState statusIcon, int subId) {
+ if (!mProviderModel) {
+ return;
+ }
+ int slotIndex = getSlotIndex(subId);
+ if (slotIndex >= SIM_SLOTS) {
+ Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+ return;
+ }
+ if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
+ return;
+ }
+ if (statusIcon.icon == R.drawable.ic_qs_no_calling_sms) {
+ if (statusIcon.visible) {
+ mInfos[slotIndex] = new CellSignalState(true,
+ statusIcon.icon, statusIcon.contentDescription, "", false);
+ } else {
+ // Whenever the no Calling & SMS state is cleared, switched to the last
+ // known call strength icon.
+ mInfos[slotIndex] = new CellSignalState(
+ true, mLastSignalLevel[slotIndex],
+ mLastSignalLevelDescription[slotIndex], "", false);
+ }
+ mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ } else {
+ mLastSignalLevel[slotIndex] = statusIcon.icon;
+ mLastSignalLevelDescription[slotIndex] = statusIcon.contentDescription;
+ // Only Shows the call strength icon when the no Calling & SMS icon is not
+ // shown.
+ if (mInfos[slotIndex].mobileSignalIconId
+ != R.drawable.ic_qs_no_calling_sms) {
+ mInfos[slotIndex] = new CellSignalState(true, statusIcon.icon,
+ statusIcon.contentDescription, "", false);
+ mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ }
+ }
+ }
+
+ @Override
public void setNoSims(boolean hasNoSims, boolean simDetected) {
if (hasNoSims) {
for (int i = 0; i < SIM_SLOTS; i++) {
@@ -118,7 +169,12 @@
private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter,
@Background Handler bgHandler, @Main Looper mainLooper,
NetworkController networkController,
- CarrierTextController.Builder carrierTextControllerBuilder) {
+ CarrierTextController.Builder carrierTextControllerBuilder, Context context) {
+ if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
+ mProviderModel = true;
+ } else {
+ mProviderModel = false;
+ }
mActivityStarter = activityStarter;
mBgHandler = bgHandler;
mNetworkController = networkController;
@@ -149,7 +205,13 @@
mCarrierDividers[1] = view.getCarrierDivider2();
for (int i = 0; i < SIM_SLOTS; i++) {
- mInfos[i] = new CellSignalState();
+ mInfos[i] = new CellSignalState(true, R.drawable.ic_qs_no_calling_sms,
+ context.getText(AccessibilityContentDescriptions.NO_CALLING).toString(),
+ "", false);
+ mLastSignalLevel[i] = TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[0];
+ mLastSignalLevelDescription[i] =
+ context.getText(AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0])
+ .toString();
mCarrierGroups[i].setOnClickListener(onClickListener);
}
view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -305,16 +367,18 @@
private final Looper mLooper;
private final NetworkController mNetworkController;
private final CarrierTextController.Builder mCarrierTextControllerBuilder;
+ private final Context mContext;
@Inject
public Builder(ActivityStarter activityStarter, @Background Handler handler,
@Main Looper looper, NetworkController networkController,
- CarrierTextController.Builder carrierTextControllerBuilder) {
+ CarrierTextController.Builder carrierTextControllerBuilder, Context context) {
mActivityStarter = activityStarter;
mHandler = handler;
mLooper = looper;
mNetworkController = networkController;
mCarrierTextControllerBuilder = carrierTextControllerBuilder;
+ mContext = context;
}
public Builder setQSCarrierGroup(QSCarrierGroup view) {
@@ -324,7 +388,7 @@
public QSCarrierGroupController build() {
return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
- mNetworkController, mCarrierTextControllerBuilder);
+ mNetworkController, mCarrierTextControllerBuilder, mContext);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
index abf230e..d4bab21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -102,6 +102,12 @@
public void onConfigChanged(Configuration newConfig) {
mView.updateNavBackDrop(newConfig, mLightBarController);
mView.updateResources();
+ if (mTileAdapter.updateNumColumns()) {
+ RecyclerView.LayoutManager lm = mView.getRecyclerView().getLayoutManager();
+ if (lm instanceof GridLayoutManager) {
+ ((GridLayoutManager) lm).setSpanCount(mTileAdapter.getNumColumns());
+ }
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 21464fd..048fdc3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -98,7 +98,7 @@
private final UiEventLogger mUiEventLogger;
private final AccessibilityDelegateCompat mAccessibilityDelegate;
private RecyclerView mRecyclerView;
- private final int mNumColumns;
+ private int mNumColumns;
@Inject
public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger) {
@@ -123,6 +123,21 @@
mRecyclerView = null;
}
+ /**
+ * Update the number of columns to show, from resources.
+ *
+ * @return {@code true} if the number of columns changed, {@code false} otherwise
+ */
+ public boolean updateNumColumns() {
+ int numColumns = mContext.getResources().getInteger(R.integer.quick_settings_num_columns);
+ if (numColumns != mNumColumns) {
+ mNumColumns = numColumns;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public int getNumColumns() {
return mNumColumns;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
index f887151..f8f1d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
@@ -144,7 +144,9 @@
setAlpha(0f);
setTranslationX((getParentWidth() - getWidth()) / 2);
setVisibility(View.VISIBLE);
- animate().alpha(1f).translationX(0).scaleX(1f).scaleY(1f).start();
+ boolean touchOnRight = event.getX() > getParentWidth() / 2;
+ float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth();
+ animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f).start();
break;
case MotionEvent.ACTION_MOVE:
mLastCropPosition = cropPosition;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index d97f644..6d64049 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -16,6 +16,8 @@
package com.android.systemui.screenshot;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
+
import android.annotation.IdRes;
import android.annotation.UiThread;
import android.content.ComponentName;
@@ -27,12 +29,23 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.view.ActionMode;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SearchEvent;
import android.view.View;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
@@ -123,8 +136,10 @@
mCallback = callback;
setContentView(R.layout.long_screenshot);
+ mWindow.setCallback(new WindowCallbacks(this::doFinish));
mWindow.getDecorView().getViewTreeObserver()
.addOnComputeInternalInsetsListener(this);
+
mPreview = findViewById(R.id.preview);
mSave = findViewById(R.id.save);
@@ -334,4 +349,130 @@
mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
}
}
+
+ private static class WindowCallbacks implements Window.Callback {
+
+ private final Runnable mFinish;
+
+ WindowCallbacks(Runnable finish) {
+ mFinish = finish;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (DEBUG_INPUT) {
+ Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK");
+ }
+ mFinish.run();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchTrackballEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public View onCreatePanelView(int featureId) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onMenuOpened(int featureId, @NonNull Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) {
+ return false;
+ }
+
+ @Override
+ public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
+ }
+
+ @Override
+ public void onContentChanged() {
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ }
+
+ @Override
+ public void onPanelClosed(int featureId, @NonNull Menu menu) {
+ }
+
+ @Override
+ public boolean onSearchRequested() {
+ return false;
+ }
+
+ @Override
+ public boolean onSearchRequested(SearchEvent searchEvent) {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
+ return null;
+ }
+
+ @Override
+ public void onActionModeStarted(ActionMode mode) {
+ }
+
+ @Override
+ public void onActionModeFinished(ActionMode mode) {
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 862c279..7aa41e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -67,10 +67,6 @@
return mFlagReader.isEnabled(R.bool.flag_brightness_slider);
}
- public boolean useNewLockscreenAnimations() {
- return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
- }
-
public boolean isPeopleTileEnabled() {
return mFlagReader.isEnabled(R.bool.flag_conversations);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index c1feaca..2f0f90d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -11,10 +11,14 @@
import android.graphics.PorterDuffXfermode
import android.graphics.RadialGradient
import android.graphics.Shader
+import android.os.SystemProperties
import android.util.AttributeSet
import android.view.View
import com.android.systemui.Interpolators
+val enableLightReveal =
+ SystemProperties.getBoolean("persist.sysui.show_new_screen_on_transitions", false)
+
/**
* Provides methods to modify the various properties of a [LightRevealScrim] to reveal between 0% to
* 100% of the view(s) underneath the scrim.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
index 0465ebf..edcf6d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
@@ -18,23 +18,19 @@
import static android.service.notification.NotificationListenerService.Ranking;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.ENABLE_NAS_FEEDBACK;
+
import android.app.NotificationManager;
-import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
import android.os.Handler;
-import android.os.Looper;
-import android.os.UserHandle;
-import android.provider.Settings;
+import android.provider.DeviceConfig;
import android.util.Pair;
-import androidx.annotation.Nullable;
-
import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.DeviceConfigProxy;
import javax.inject.Inject;
@@ -45,10 +41,10 @@
* should show an indicator.
*/
@SysUISingleton
-public class AssistantFeedbackController extends ContentObserver {
- private final Uri FEEDBACK_URI
- = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_FEEDBACK_ENABLED);
- private ContentResolver mResolver;
+public class AssistantFeedbackController {
+ private final Context mContext;
+ private final Handler mHandler;
+ private final DeviceConfigProxy mDeviceConfigProxy;
public static final int STATUS_UNCHANGED = 0;
public static final int STATUS_ALERTED = 1;
@@ -56,34 +52,39 @@
public static final int STATUS_PROMOTED = 3;
public static final int STATUS_DEMOTED = 4;
- private boolean mFeedbackEnabled;
+ private volatile boolean mFeedbackEnabled;
+
+ private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
+ new DeviceConfig.OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (properties.getKeyset().contains(ENABLE_NAS_FEEDBACK)) {
+ mFeedbackEnabled = properties.getBoolean(
+ ENABLE_NAS_FEEDBACK, false);
+ }
+ }
+ };
/** Injected constructor */
@Inject
- public AssistantFeedbackController(Context context) {
- super(new Handler(Looper.getMainLooper()));
- mResolver = context.getContentResolver();
- mResolver.registerContentObserver(FEEDBACK_URI, false, this, UserHandle.USER_ALL);
- update(null);
+ public AssistantFeedbackController(@Main Handler handler,
+ Context context, DeviceConfigProxy proxy) {
+ mHandler = handler;
+ mContext = context;
+ mDeviceConfigProxy = proxy;
+ mFeedbackEnabled = mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+ ENABLE_NAS_FEEDBACK, false);
+ mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+ this::postToHandler, mPropertiesChangedListener);
}
- @Override
- public void onChange(boolean selfChange, @Nullable Uri uri, int flags) {
- update(uri);
- }
-
- @VisibleForTesting
- public void update(@Nullable Uri uri) {
- if (uri == null || FEEDBACK_URI.equals(uri)) {
- mFeedbackEnabled = Settings.Global.getInt(mResolver,
- Settings.Global.NOTIFICATION_FEEDBACK_ENABLED, 0)
- != 0;
- }
+ private void postToHandler(Runnable r) {
+ this.mHandler.post(r);
}
/**
- * Determines whether to show any user controls related to the assistant. This is based on the
- * settings flag {@link Settings.Global.NOTIFICATION_FEEDBACK_ENABLED}
+ * Determines whether to show any user controls related to the assistant based on the
+ * DeviceConfig flag value
*/
public boolean isFeedbackEnabled() {
return mFeedbackEnabled;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 85d8df8..8c2fa33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -29,7 +29,6 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
@@ -55,7 +54,6 @@
private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
private final Resources mResources;
private final BatteryController mBatteryController;
- private final FeatureFlags mFeatureFlags;
private boolean mDozeAlwaysOn;
private boolean mControlScreenOffAnimation;
@@ -67,8 +65,7 @@
AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
PowerManager powerManager,
BatteryController batteryController,
- TunerService tunerService,
- FeatureFlags featureFlags) {
+ TunerService tunerService) {
mResources = resources;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mAlwaysOnPolicy = alwaysOnDisplayPolicy;
@@ -77,7 +74,6 @@
mControlScreenOffAnimation = !getDisplayNeedsBlanking();
mPowerManager = powerManager;
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
- mFeatureFlags = featureFlags;
tunerService.addTunable(
this,
@@ -204,7 +200,8 @@
* then abruptly showing AOD.
*/
public boolean shouldControlUnlockedScreenOff() {
- return getAlwaysOn() && mFeatureFlags.useNewLockscreenAnimations();
+ return getAlwaysOn() && SystemProperties.getBoolean(
+ "persist.sysui.show_new_screen_on_transitions", false);
}
private boolean getBoolean(String propName, int resId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 041a97e..e63902f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -35,6 +35,7 @@
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+import static com.android.systemui.statusbar.LightRevealScrimKt.getEnableLightReveal;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -179,7 +180,6 @@
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -440,7 +440,6 @@
private final KeyguardViewMediator mKeyguardViewMediator;
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSlider.Factory mBrightnessSliderFactory;
- private final FeatureFlags mFeatureFlags;
private final List<ExpansionChangedListener> mExpansionChangedListeners;
@@ -763,8 +762,7 @@
Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
- BrightnessSlider.Factory brightnessSliderFactory,
- FeatureFlags featureFlags) {
+ BrightnessSlider.Factory brightnessSliderFactory) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
@@ -842,7 +840,6 @@
mDemoModeController = demoModeController;
mNotificationIconAreaController = notificationIconAreaController;
mBrightnessSliderFactory = brightnessSliderFactory;
- mFeatureFlags = featureFlags;
mExpansionChangedListeners = new ArrayList<>();
@@ -1184,11 +1181,9 @@
mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
- if (mFeatureFlags.useNewLockscreenAnimations() && mDozeParameters.getAlwaysOn()) {
+ if (getEnableLightReveal()) {
mLightRevealScrim.setVisibility(View.VISIBLE);
mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
- } else {
- mLightRevealScrim.setVisibility(View.GONE);
}
mNotificationPanelViewController.initDependencies(
@@ -3619,7 +3614,7 @@
@Override
public void onDozeAmountChanged(float linear, float eased) {
- if (mFeatureFlags.useNewLockscreenAnimations()) {
+ if (getEnableLightReveal()) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 00acd7b..8620376 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -42,8 +42,8 @@
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import java.util.List;
@@ -66,7 +66,7 @@
/**
* Display the no calling & SMS icons.
*/
- void setNoCallingIcons(String slot, List<NoCallingIconState> states);
+ void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states);
public void setIconVisibility(String slot, boolean b);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 5e8d590..f0c8527 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -34,8 +34,8 @@
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -206,6 +206,7 @@
Collections.reverse(iconStates);
for (MobileIconState state : iconStates) {
+
StatusBarIconHolder holder = mobileSlot.getHolderForTag(state.subId);
if (holder == null) {
holder = StatusBarIconHolder.fromMobileIconState(state);
@@ -218,23 +219,25 @@
}
/**
- * Accept a list of NoCallingIconStates, and show them in the same slot
+ * Accept a list of CallIndicatorIconStates, and show them in the same slot
* @param slot StatusBar slot
* @param states All of the no Calling & SMS icon states
*/
@Override
- public void setNoCallingIcons(String slot, List<NoCallingIconState> states) {
+ public void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states) {
Slot noCallingSlot = getSlot(slot);
int slotIndex = getSlotIndex(slot);
-
- for (NoCallingIconState state : states) {
+ for (CallIndicatorIconState state : states) {
StatusBarIconHolder holder = noCallingSlot.getHolderForTag(state.subId);
if (holder == null) {
- holder = StatusBarIconHolder.fromNoCallingState(mContext, state);
- holder.setVisible(state.visible);
+ holder = StatusBarIconHolder.fromCallIndicatorState(mContext, state);
setIcon(slotIndex, holder);
} else {
- holder.setVisible(state.visible);
+ int resId = state.isNoCalling ? state.noCallingResId : state.callStrengthResId;
+ String contentDescription = state.isNoCalling
+ ? state.noCallingDescription : state.callStrengthDescription;
+ holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
+ Icon.createWithResource(mContext, resId), 0, 0, contentDescription));
setIcon(slotIndex, holder);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
index 36a0e63..a1a2d30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -22,8 +22,8 @@
import android.os.UserHandle;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
/**
@@ -72,14 +72,18 @@
}
/**
- * Creates a new StatusBarIconHolder from a NoCallingIconState.
+ * Creates a new StatusBarIconHolder from a CallIndicatorIconState.
*/
- public static StatusBarIconHolder fromNoCallingState(
- Context context, NoCallingIconState state) {
+ public static StatusBarIconHolder fromCallIndicatorState(
+ Context context, CallIndicatorIconState state) {
StatusBarIconHolder holder = new StatusBarIconHolder();
+ int resId = state.isNoCalling ? state.noCallingResId : state.callStrengthResId;
+ String contentDescription = state.isNoCalling
+ ? state.noCallingDescription : state.callStrengthDescription;
holder.mIcon = new StatusBarIcon(UserHandle.SYSTEM, context.getPackageName(),
- Icon.createWithResource(context, state.resId), 0, 0, null);
+ Icon.createWithResource(context, resId), 0, 0, contentDescription);
holder.mTag = state.subId;
+ holder.setVisible(true);
return holder;
}
@@ -92,6 +96,10 @@
return mIcon;
}
+ public void setIcon(StatusBarIcon icon) {
+ mIcon = icon;
+ }
+
@Nullable
public WifiIconState getWifiState() {
return mWifiState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index f6165f6..7bc1bb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -22,6 +22,7 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -39,7 +40,7 @@
public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,
SecurityController.SecurityControllerCallback, Tunable {
private static final String TAG = "StatusBarSignalPolicy";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.INFO);
private final String mSlotAirplane;
private final String mSlotMobile;
@@ -67,7 +68,8 @@
private boolean mWifiVisible = false;
private ArrayList<MobileIconState> mMobileStates = new ArrayList<MobileIconState>();
- private ArrayList<NoCallingIconState> mNoCallingStates = new ArrayList<NoCallingIconState>();
+ private ArrayList<CallIndicatorIconState> mCallIndicatorStates =
+ new ArrayList<CallIndicatorIconState>();
private WifiIconState mWifiIconState = new WifiIconState();
public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {
@@ -201,19 +203,25 @@
}
@Override
- public void setNoCallingStatus(boolean noCalling, int subId) {
+ public void setCallIndicator(IconState statusIcon, int subId) {
if (DEBUG) {
- Log.d(TAG, "setNoCallingStatus: "
- + "noCalling = " + noCalling + ","
+ Log.d(TAG, "setCallIndicator: "
+ + "statusIcon = " + statusIcon + ","
+ "subId = " + subId);
}
- NoCallingIconState state = getNoCallingState(subId);
+ CallIndicatorIconState state = getNoCallingState(subId);
if (state == null) {
return;
}
- state.visible = noCalling;
- mIconController.setNoCallingIcons(
- mSlotNoCalling, NoCallingIconState.copyStates(mNoCallingStates));
+ if (statusIcon.icon == R.drawable.ic_qs_no_calling_sms) {
+ state.isNoCalling = statusIcon.visible;
+ state.noCallingDescription = statusIcon.contentDescription;
+ } else {
+ state.callStrengthResId = statusIcon.icon;
+ state.callStrengthDescription = statusIcon.contentDescription;
+ }
+ mIconController.setCallIndicatorIcons(
+ mSlotNoCalling, CallIndicatorIconState.copyStates(mCallIndicatorStates));
}
@Override
@@ -273,8 +281,8 @@
}
}
- private NoCallingIconState getNoCallingState(int subId) {
- for (NoCallingIconState state : mNoCallingStates) {
+ private CallIndicatorIconState getNoCallingState(int subId) {
+ for (CallIndicatorIconState state : mCallIndicatorStates) {
if (state.subId == subId) {
return state;
}
@@ -315,23 +323,25 @@
}
mIconController.removeAllIconsForSlot(mSlotMobile);
+ mIconController.removeAllIconsForSlot(mSlotNoCalling);
mMobileStates.clear();
- List<NoCallingIconState> noCallingStates = new ArrayList<NoCallingIconState>();
- noCallingStates.addAll(mNoCallingStates);
- mNoCallingStates.clear();
+ List<CallIndicatorIconState> noCallingStates = new ArrayList<CallIndicatorIconState>();
+ noCallingStates.addAll(mCallIndicatorStates);
+ mCallIndicatorStates.clear();
final int n = subs.size();
for (int i = 0; i < n; i++) {
mMobileStates.add(new MobileIconState(subs.get(i).getSubscriptionId()));
boolean isNewSub = true;
- for (NoCallingIconState state : noCallingStates) {
+ for (CallIndicatorIconState state : noCallingStates) {
if (state.subId == subs.get(i).getSubscriptionId()) {
- mNoCallingStates.add(state);
+ mCallIndicatorStates.add(state);
isNewSub = false;
break;
}
}
if (isNewSub) {
- mNoCallingStates.add(new NoCallingIconState(subs.get(i).getSubscriptionId()));
+ mCallIndicatorStates.add(
+ new CallIndicatorIconState(subs.get(i).getSubscriptionId()));
}
}
}
@@ -425,14 +435,18 @@
/**
* Stores the StatusBar state for no Calling & SMS.
*/
- public static class NoCallingIconState {
- public boolean visible;
- public int resId;
+ public static class CallIndicatorIconState {
+ public boolean isNoCalling;
+ public int noCallingResId;
+ public int callStrengthResId;
public int subId;
+ public String noCallingDescription;
+ public String callStrengthDescription;
- private NoCallingIconState(int subId) {
+ private CallIndicatorIconState(int subId) {
this.subId = subId;
- this.resId = R.drawable.ic_qs_no_calling_sms;
+ this.noCallingResId = R.drawable.ic_qs_no_calling_sms;
+ this.callStrengthResId = TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[0];
}
@Override
@@ -441,27 +455,36 @@
if (o == null || getClass() != o.getClass()) {
return false;
}
- NoCallingIconState that = (NoCallingIconState) o;
- return visible == that.visible
- && resId == that.resId
- && subId == that.subId;
+ CallIndicatorIconState that = (CallIndicatorIconState) o;
+ return isNoCalling == that.isNoCalling
+ && noCallingResId == that.noCallingResId
+ && callStrengthResId == that.callStrengthResId
+ && subId == that.subId
+ && noCallingDescription == that.noCallingDescription
+ && callStrengthDescription == that.callStrengthDescription;
+
}
@Override
public int hashCode() {
- return Objects.hash(visible, resId, subId);
+ return Objects.hash(isNoCalling, noCallingResId,
+ callStrengthResId, subId, noCallingDescription, callStrengthDescription);
}
- private void copyTo(NoCallingIconState other) {
- other.visible = visible;
- other.resId = resId;
+ private void copyTo(CallIndicatorIconState other) {
+ other.isNoCalling = isNoCalling;
+ other.noCallingResId = noCallingResId;
+ other.callStrengthResId = callStrengthResId;
other.subId = subId;
+ other.noCallingDescription = noCallingDescription;
+ other.callStrengthDescription = callStrengthDescription;
}
- private static List<NoCallingIconState> copyStates(List<NoCallingIconState> inStates) {
- ArrayList<NoCallingIconState> outStates = new ArrayList<>();
- for (NoCallingIconState state : inStates) {
- NoCallingIconState copy = new NoCallingIconState(state.subId);
+ private static List<CallIndicatorIconState> copyStates(
+ List<CallIndicatorIconState> inStates) {
+ ArrayList<CallIndicatorIconState> outStates = new ArrayList<>();
+ for (CallIndicatorIconState state : inStates) {
+ CallIndicatorIconState copy = new CallIndicatorIconState(state.subId);
state.copyTo(copy);
outStates.add(copy);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index b572c57..9e9533d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -47,7 +47,6 @@
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -201,8 +200,7 @@
DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
- BrightnessSlider.Factory brightnessSliderFactory,
- FeatureFlags featureFlags) {
+ BrightnessSlider.Factory brightnessSliderFactory) {
return new StatusBar(
context,
notificationsController,
@@ -281,7 +279,6 @@
notificationShadeDepthController,
statusBarTouchableRegionManager,
notificationIconAreaController,
- brightnessSliderFactory,
- featureFlags);
+ brightnessSliderFactory);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index ccaa1f4..5ff8970 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -36,6 +36,7 @@
* the current or specified Looper.
*/
public class CallbackHandler extends Handler implements EmergencyListener, SignalCallback {
+ private static final String TAG = "CallbackHandler";
private static final int MSG_EMERGENCE_CHANGED = 0;
private static final int MSG_SUBS_CHANGED = 1;
private static final int MSG_NO_SIM_VISIBLE_CHANGED = 2;
@@ -198,17 +199,17 @@
}
@Override
- public void setNoCallingStatus(boolean noCalling, int subId) {
+ public void setCallIndicator(IconState statusIcon, int subId) {
String log = new StringBuilder()
.append(SSDF.format(System.currentTimeMillis())).append(",")
- .append("setNoCallingStatus: ")
- .append("noCalling=").append(noCalling).append(",")
+ .append("setCallIndicator: ")
+ .append("statusIcon=").append(statusIcon).append(",")
.append("subId=").append(subId)
.toString();
recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
- signalCluster.setNoCallingStatus(noCalling, subId);
+ signalCluster.setCallIndicator(statusIcon, subId);
}
});
}
@@ -226,24 +227,11 @@
@Override
public void setNoSims(boolean show, boolean simDetected) {
- String log = new StringBuilder()
- .append(SSDF.format(System.currentTimeMillis())).append(",")
- .append("setNoSims: ")
- .append("show=").append(show).append(",")
- .append("simDetected=").append(simDetected)
- .toString();
- recordLastCallback(log);
obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, simDetected ? 1 : 0).sendToTarget();
}
@Override
public void setMobileDataEnabled(boolean enabled) {
- String log = new StringBuilder()
- .append(SSDF.format(System.currentTimeMillis())).append(",")
- .append("setMobileDataEnabled: ")
- .append("enabled=").append(enabled)
- .toString();
- recordLastCallback(log);
obtainMessage(MSG_MOBILE_DATA_ENABLED_CHANGED, enabled ? 1 : 0, 0).sendToTarget();
}
@@ -283,7 +271,8 @@
}
protected void recordLastCallback(String callback) {
- mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)] = callback;
+ mHistory[mHistoryIndex] = callback;
+ mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
}
/**
@@ -293,7 +282,9 @@
pw.println(" - CallbackHandler -----");
int size = 0;
for (int i = 0; i < HISTORY_SIZE; i++) {
- if (mHistory[i] != null) size++;
+ if (mHistory[i] != null) {
+ size++;
+ }
}
// Print out the previous states in ordered number.
for (int i = mHistoryIndex + HISTORY_SIZE - 1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 0fe338e..1ab7652 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -26,6 +26,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings.Global;
+import android.telephony.AccessNetworkConstants;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrengthCdma;
import android.telephony.ServiceState;
@@ -34,12 +35,18 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
+import android.telephony.ims.RegistrationManager.RegistrationCallback;
import android.text.Html;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.AccessibilityContentDescriptions;
import com.android.settingslib.SignalIcon.MobileIconGroup;
import com.android.settingslib.SignalIcon.MobileState;
import com.android.settingslib.Utils;
@@ -65,13 +72,19 @@
*/
public class MobileSignalController extends SignalController<MobileState, MobileIconGroup> {
private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
-
+ private static final int STATUS_HISTORY_SIZE = 64;
+ private static final int IMS_TYPE_WWAN = 1;
+ private static final int IMS_TYPE_WLAN = 2;
+ private static final int IMS_TYPE_WLAN_CROSS_SIM = 3;
private final TelephonyManager mPhone;
+ private final ImsMmTelManager mImsMmTelManager;
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
private final String mNetworkNameSeparator;
private final ContentObserver mObserver;
private final boolean mProviderModel;
+ private final Handler mReceiverHandler;
+ private int mImsType = IMS_TYPE_WWAN;
// Save entire info for logging, we only use the id.
final SubscriptionInfo mSubscriptionInfo;
// @VisibleForDemoMode
@@ -86,16 +99,21 @@
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
private ServiceState mServiceState;
private SignalStrength mSignalStrength;
+ private int mLastLevel;
private MobileIconGroup mDefaultIcons;
private Config mConfig;
@VisibleForTesting
boolean mInflateSignalStrengths = false;
private MobileStatusTracker.Callback mCallback;
+ private RegistrationCallback mRegistrationCallback;
+ private int mLastWwanLevel;
+ private int mLastWlanLevel;
+ private int mLastWlanCrossSimLevel;
@VisibleForTesting
MobileStatusTracker mMobileStatusTracker;
- // Save the previous HISTORY_SIZE states for logging.
- private final String[] mMobileStatusHistory = new String[HISTORY_SIZE];
+ // Save the previous STATUS_HISTORY_SIZE states for logging.
+ private final String[] mMobileStatusHistory = new String[STATUS_HISTORY_SIZE];
// Where to copy the next state into.
private int mMobileStatusHistoryIndex;
@@ -116,6 +134,7 @@
.toString();
mNetworkNameDefault = getTextIfExists(
com.android.internal.R.string.lockscreen_carrier_default).toString();
+ mReceiverHandler = new Handler(receiverLooper);
mNetworkToIconLookup = mapIconSets(mConfig);
mDefaultIcons = getDefaultIcons(mConfig);
@@ -133,6 +152,8 @@
}
};
mCallback = new MobileStatusTracker.Callback() {
+ private String mLastStatus;
+
@Override
public void onMobileStatusChanged(boolean updateTelephony,
MobileStatus mobileStatus) {
@@ -141,11 +162,15 @@
+ " updateTelephony=" + updateTelephony
+ " mobileStatus=" + mobileStatus.toString());
}
- String status = new StringBuilder()
- .append(SSDF.format(System.currentTimeMillis())).append(",")
- .append(mobileStatus.toString())
- .toString();
- recordLastMobileStatus(status);
+ String currentStatus = mobileStatus.toString();
+ if (!currentStatus.equals(mLastStatus)) {
+ mLastStatus = currentStatus;
+ String status = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append(currentStatus)
+ .toString();
+ recordLastMobileStatus(status);
+ }
updateMobileStatus(mobileStatus);
if (updateTelephony) {
updateTelephony();
@@ -154,6 +179,53 @@
}
}
};
+
+ mRegistrationCallback = new RegistrationCallback() {
+ @Override
+ public void onRegistered(ImsRegistrationAttributes attributes) {
+ Log.d(mTag, "onRegistered: " + "attributes=" + attributes);
+ int imsTransportType = attributes.getTransportType();
+ int registrationAttributes = attributes.getAttributeFlags();
+ if (imsTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
+ mImsType = IMS_TYPE_WWAN;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWwanLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWwanLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ } else if (imsTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
+ if (registrationAttributes == 0) {
+ mImsType = IMS_TYPE_WLAN;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanLevel, /* isWifi= */true),
+ getCallStrengthDescription(mLastWlanLevel, /* isWifi= */true));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ } else if (registrationAttributes
+ == ImsRegistrationAttributes.ATTR_EPDG_OVER_CELL_INTERNET) {
+ mImsType = IMS_TYPE_WLAN_CROSS_SIM;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanCrossSimLevel, /* isWifi= */false),
+ getCallStrengthDescription(
+ mLastWlanCrossSimLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ }
+ }
+
+ @Override
+ public void onUnregistered(ImsReasonInfo info) {
+ Log.d(mTag, "onDeregistered: " + "info=" + info);
+ mImsType = IMS_TYPE_WWAN;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWwanLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWwanLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ };
+ mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(info.getSubscriptionId());
mMobileStatusTracker = new MobileStatusTracker(mPhone, receiverLooper,
info, mDefaults, mCallback);
mProviderModel = FeatureFlagUtils.isEnabled(
@@ -202,14 +274,41 @@
mContext.getContentResolver().registerContentObserver(Global.getUriFor(
Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
true, mObserver);
+ if (mProviderModel) {
+ mReceiverHandler.post(mTryRegisterIms);
+ }
}
+ // There is no listener to monitor whether the IMS service is ready, so we have to retry the
+ // IMS registration.
+ private final Runnable mTryRegisterIms = new Runnable() {
+ private static final int MAX_RETRY = 12;
+ private int mRetryCount;
+
+ @Override
+ public void run() {
+ try {
+ mRetryCount++;
+ mImsMmTelManager.registerImsRegistrationCallback(
+ mReceiverHandler::post, mRegistrationCallback);
+ Log.d(mTag, "registerImsRegistrationCallback succeeded");
+ } catch (RuntimeException | ImsException e) {
+ if (mRetryCount < MAX_RETRY) {
+ Log.e(mTag, mRetryCount + " registerImsRegistrationCallback failed", e);
+ // Wait for 5 seconds to retry
+ mReceiverHandler.postDelayed(mTryRegisterIms, 5000);
+ }
+ }
+ }
+ };
+
/**
* Stop listening for phone state changes.
*/
public void unregisterListener() {
mMobileStatusTracker.setListening(false);
mContext.getContentResolver().unregisterContentObserver(mObserver);
+ mImsMmTelManager.unregisterImsRegistrationCallback(mRegistrationCallback);
}
private void updateInflateSignalStrength() {
@@ -452,9 +551,9 @@
/**
* Extracts the CellSignalStrengthCdma from SignalStrength then returns the level
*/
- private final int getCdmaLevel() {
+ private int getCdmaLevel(SignalStrength signalStrength) {
List<CellSignalStrengthCdma> signalStrengthCdma =
- mSignalStrength.getCellSignalStrengths(CellSignalStrengthCdma.class);
+ signalStrength.getCellSignalStrengths(CellSignalStrengthCdma.class);
if (!signalStrengthCdma.isEmpty()) {
return signalStrengthCdma.get(0).getLevel();
}
@@ -467,6 +566,7 @@
mCurrentState.dataSim = mobileStatus.dataSim;
mCurrentState.carrierNetworkChangeMode = mobileStatus.carrierNetworkChangeMode;
mDataState = mobileStatus.dataState;
+ notifyMobileLevelChangeIfNecessary(mobileStatus.signalStrength);
mSignalStrength = mobileStatus.signalStrength;
mTelephonyDisplayInfo = mobileStatus.telephonyDisplayInfo;
int lastVoiceState = mServiceState != null ? mServiceState.getState() : -1;
@@ -481,9 +581,117 @@
&& (lastVoiceState == -1
|| (lastVoiceState == ServiceState.STATE_IN_SERVICE
|| currentVoiceState == ServiceState.STATE_IN_SERVICE))) {
- notifyNoCallingStatusChange(
- currentVoiceState != ServiceState.STATE_IN_SERVICE,
- mSubscriptionInfo.getSubscriptionId());
+ boolean isNoCalling = currentVoiceState != ServiceState.STATE_IN_SERVICE;
+ IconState statusIcon = new IconState(isNoCalling, R.drawable.ic_qs_no_calling_sms,
+ getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ }
+
+ private int getCallStrengthIcon(int level, boolean isWifi) {
+ return isWifi ? TelephonyIcons.WIFI_CALL_STRENGTH_ICONS[level]
+ : TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[level];
+ }
+
+ private String getCallStrengthDescription(int level, boolean isWifi) {
+ return isWifi
+ ? getTextIfExists(AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[level])
+ .toString()
+ : getTextIfExists(AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[level])
+ .toString();
+ }
+
+ void refreshCallIndicator(SignalCallback callback) {
+ boolean isNoCalling = mServiceState != null
+ && mServiceState.getState() != ServiceState.STATE_IN_SERVICE;
+ IconState statusIcon = new IconState(isNoCalling, R.drawable.ic_qs_no_calling_sms,
+ getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
+ callback.setCallIndicator(statusIcon, mSubscriptionInfo.getSubscriptionId());
+
+ switch (mImsType) {
+ case IMS_TYPE_WWAN:
+ statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWwanLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWwanLevel, /* isWifi= */false));
+ break;
+ case IMS_TYPE_WLAN:
+ statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanLevel, /* isWifi= */true),
+ getCallStrengthDescription(mLastWlanLevel, /* isWifi= */true));
+ break;
+ case IMS_TYPE_WLAN_CROSS_SIM:
+ statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanCrossSimLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWlanCrossSimLevel, /* isWifi= */false));
+ }
+ callback.setCallIndicator(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ void notifyWifiLevelChange(int level) {
+ if (!mProviderModel) {
+ return;
+ }
+ Log.d("mTag", "notifyWifiLevelChange " + mImsType);
+ mLastWlanLevel = level;
+ if (mImsType != IMS_TYPE_WLAN) {
+ return;
+ }
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(level, /* isWifi= */true),
+ getCallStrengthDescription(level, /* isWifi= */true));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ void notifyDefaultMobileLevelChange(int level) {
+ if (!mProviderModel) {
+ return;
+ }
+ Log.d("mTag", "notifyDefaultMobileLevelChange " + mImsType);
+ mLastWlanCrossSimLevel = level;
+ if (mImsType != IMS_TYPE_WLAN_CROSS_SIM) {
+ return;
+ }
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(level, /* isWifi= */false),
+ getCallStrengthDescription(level, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ void notifyMobileLevelChangeIfNecessary(SignalStrength signalStrength) {
+ if (!mProviderModel) {
+ return;
+ }
+ int newLevel = getSignalLevel(signalStrength);
+ if (newLevel != mLastLevel) {
+ mLastLevel = newLevel;
+ Log.d("mTag", "notifyMobileLevelChangeIfNecessary " + mImsType);
+ mLastWwanLevel = newLevel;
+ if (mImsType == IMS_TYPE_WWAN) {
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(newLevel, /* isWifi= */false),
+ getCallStrengthDescription(newLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ if (mCurrentState.dataSim) {
+ mNetworkController.notifyDefaultMobileLevelChange(newLevel);
+ }
+ }
+ }
+
+ int getSignalLevel(SignalStrength signalStrength) {
+ if (signalStrength == null) {
+ return 0;
+ }
+ if (!signalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
+ return getCdmaLevel(signalStrength);
+ } else {
+ return signalStrength.getLevel();
}
}
@@ -501,11 +709,7 @@
checkDefaultData();
mCurrentState.connected = Utils.isInService(mServiceState) && mSignalStrength != null;
if (mCurrentState.connected) {
- if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
- mCurrentState.level = getCdmaLevel();
- } else {
- mCurrentState.level = mSignalStrength.getLevel();
- }
+ mCurrentState.level = getSignalLevel(mSignalStrength);
}
String iconKey = getIconKey(mTelephonyDisplayInfo);
@@ -577,7 +781,13 @@
}
private void recordLastMobileStatus(String mobileStatus) {
- mMobileStatusHistory[mMobileStatusHistoryIndex++ & (HISTORY_SIZE - 1)] = mobileStatus;
+ mMobileStatusHistory[mMobileStatusHistoryIndex] = mobileStatus;
+ mMobileStatusHistoryIndex = (mMobileStatusHistoryIndex + 1) % STATUS_HISTORY_SIZE;
+ }
+
+ @VisibleForTesting
+ void setImsType(int imsType) {
+ mImsType = imsType;
}
@Override
@@ -592,15 +802,17 @@
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
pw.println(" MobileStatusHistory");
int size = 0;
- for (int i = 0; i < HISTORY_SIZE; i++) {
- if (mMobileStatusHistory[i] != null) size++;
+ for (int i = 0; i < STATUS_HISTORY_SIZE; i++) {
+ if (mMobileStatusHistory[i] != null) {
+ size++;
+ }
}
// Print out the previous states in ordered number.
- for (int i = mMobileStatusHistoryIndex + HISTORY_SIZE - 1;
- i >= mMobileStatusHistoryIndex + HISTORY_SIZE - size; i--) {
+ for (int i = mMobileStatusHistoryIndex + STATUS_HISTORY_SIZE - 1;
+ i >= mMobileStatusHistoryIndex + STATUS_HISTORY_SIZE - size; i--) {
pw.println(" Previous MobileStatus("
- + (mMobileStatusHistoryIndex + HISTORY_SIZE - i) + "): "
- + mMobileStatusHistory[i & (HISTORY_SIZE - 1)]);
+ + (mMobileStatusHistoryIndex + STATUS_HISTORY_SIZE - i) + "): "
+ + mMobileStatusHistory[i & (STATUS_HISTORY_SIZE - 1)]);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index e60d5c5..0a9fead 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -53,7 +53,7 @@
/**
* Callback for listeners to be able to update the state of any UI tracking connectivity
- * @param statusIcon the icon that should be shown in the status bar
+ * @param statusIcon the icon that should be shown in the status bar
* @param qsIcon the icon to show in Quick Settings
* @param statusType the resId of the data type icon (e.g. LTE) to show in the status bar
* @param qsType similar to above, the resId of the data type icon to show in Quick Settings
@@ -95,11 +95,11 @@
boolean noNetworksAvailable) {}
/**
- * Callback for listeners to be able to update the no calling & SMS status
- * @param noCalling whether the calling and SMS is not working.
+ * Callback for listeners to be able to update the call indicator
+ * @param statusIcon the icon for the call indicator
* @param subId subscription ID for which to update the UI
*/
- default void setNoCallingStatus(boolean noCalling, int subId) {}
+ default void setCallIndicator(IconState statusIcon, int subId) {}
}
public interface EmergencyListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 80c7811..9f92142 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -554,6 +554,20 @@
return controller != null ? controller.getNetworkNameForCarrierWiFi() : "";
}
+ void notifyWifiLevelChange(int level) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
+ mobileSignalController.notifyWifiLevelChange(level);
+ }
+ }
+
+ void notifyDefaultMobileLevelChange(int level) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
+ mobileSignalController.notifyDefaultMobileLevelChange(level);
+ }
+ }
+
private void notifyControllersMobileDataChanged() {
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
@@ -623,6 +637,9 @@
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.notifyListeners(cb);
+ if (mProviderModel) {
+ mobileSignalController.refreshCallIndicator(cb);
+ }
}
mCallbackHandler.setListening(cb, true);
}
@@ -1272,7 +1289,8 @@
}
private void recordLastNetworkCallback(String callback) {
- mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)] = callback;
+ mHistory[mHistoryIndex] = callback;
+ mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
}
private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index 554145e..4b6722c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -23,6 +23,7 @@
import com.android.settingslib.SignalIcon.IconGroup;
import com.android.settingslib.SignalIcon.State;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.io.PrintWriter;
@@ -167,8 +168,8 @@
}
}
- protected final void notifyNoCallingStatusChange(boolean noCalling, int subId) {
- mCallbackHandler.setNoCallingStatus(noCalling, subId);
+ protected final void notifyCallStateChange(IconState statusIcon, int subId) {
+ mCallbackHandler.setCallIndicator(statusIcon, subId);
}
/**
@@ -187,7 +188,8 @@
* and last value of any state data.
*/
protected void recordLastState() {
- mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)].copyFrom(mLastState);
+ mHistory[mHistoryIndex].copyFrom(mLastState);
+ mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
}
public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 1838391..019ab47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -680,11 +680,7 @@
if (item.isAddUser) {
iconRes = R.drawable.ic_add_circle;
} else if (item.isGuest) {
- if (item.isCurrent) {
- iconRes = R.drawable.ic_exit_to_app;
- } else {
- iconRes = R.drawable.ic_avatar_guest_user;
- }
+ iconRes = R.drawable.ic_avatar_guest_user;
} else {
iconRes = R.drawable.ic_avatar_user;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 1fd2ccb..47207d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -202,6 +202,7 @@
mCurrentState.connected = mWifiTracker.connected;
mCurrentState.ssid = mWifiTracker.ssid;
mCurrentState.rssi = mWifiTracker.rssi;
+ notifyWifiLevelChangeIfNecessary(mWifiTracker.level);
mCurrentState.level = mWifiTracker.level;
mCurrentState.statusLabel = mWifiTracker.statusLabel;
mCurrentState.isCarrierMerged = mWifiTracker.isCarrierMerged;
@@ -211,6 +212,12 @@
: mUnmergedWifiIconGroup;
}
+ void notifyWifiLevelChangeIfNecessary(int level) {
+ if (level != mCurrentState.level) {
+ mNetworkController.notifyWifiLevelChange(level);
+ }
+ }
+
boolean isCarrierMergedWifi(int subId) {
return mCurrentState.isDefault
&& mCurrentState.isCarrierMerged && (mCurrentState.subId == subId);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 09335af..b67574d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -109,7 +109,7 @@
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel),
(OnClickListener) null);
dialog.setButton(DialogInterface.BUTTON_POSITIVE,
- context.getString(R.string.qs_customize_remove), new OnClickListener() {
+ context.getString(R.string.guest_exit_guest_dialog_remove), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Tell the tuner (in main SysUI process) to clear all its settings.
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 6e7aed0..afeda967 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -45,6 +45,7 @@
import android.service.notification.ZenModeConfig;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.view.View;
import androidx.annotation.NonNull;
@@ -86,10 +87,12 @@
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
import java.util.function.Supplier;
@@ -248,38 +251,19 @@
});
mSysuiProxy = new Bubbles.SysuiProxy() {
- private <T> T executeBlockingForResult(Supplier<T> runnable, Executor executor,
- Class clazz) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- return runnable.get();
- }
- final T[] result = (T[]) Array.newInstance(clazz, 1);
- final CountDownLatch latch = new CountDownLatch(1);
- executor.execute(() -> {
- result[0] = runnable.get();
- latch.countDown();
- });
- try {
- latch.await();
- return result[0];
- } catch (InterruptedException e) {
- return null;
- }
- }
-
@Override
- @Nullable
- public BubbleEntry getPendingOrActiveEntry(String key) {
- return executeBlockingForResult(() -> {
+ public void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback) {
+ sysuiMainExecutor.execute(() -> {
NotificationEntry entry =
mNotificationEntryManager.getPendingOrActiveNotif(key);
- return entry == null ? null : notifToBubbleEntry(entry);
- }, sysuiMainExecutor, BubbleEntry.class);
+ callback.accept(entry == null ? null : notifToBubbleEntry(entry));
+ });
}
@Override
- public List<BubbleEntry> getShouldRestoredEntries(ArraySet<String> savedBubbleKeys) {
- return executeBlockingForResult(() -> {
+ public void getShouldRestoredEntries(ArraySet<String> savedBubbleKeys,
+ Consumer<List<BubbleEntry>> callback) {
+ sysuiMainExecutor.execute(() -> {
List<BubbleEntry> result = new ArrayList<>();
List<NotificationEntry> activeEntries =
mNotificationEntryManager.getActiveNotificationsForCurrentUser();
@@ -291,27 +275,8 @@
result.add(notifToBubbleEntry(entry));
}
}
- return result;
- }, sysuiMainExecutor, List.class);
- }
-
- @Override
- public boolean isNotificationShadeExpand() {
- return executeBlockingForResult(() -> {
- return mNotificationShadeWindowController.getPanelExpanded();
- }, sysuiMainExecutor, Boolean.class);
- }
-
- @Override
- public boolean shouldBubbleUp(String key) {
- return executeBlockingForResult(() -> {
- final NotificationEntry entry =
- mNotificationEntryManager.getPendingOrActiveNotif(key);
- if (entry != null) {
- return mNotificationInterruptStateProvider.shouldBubbleUp(entry);
- }
- return false;
- }, sysuiMainExecutor, Boolean.class);
+ callback.accept(result);
+ });
}
@Override
@@ -587,7 +552,20 @@
}
void onRankingUpdate(RankingMap rankingMap) {
- mBubbles.onRankingUpdated(rankingMap);
+ String[] orderedKeys = rankingMap.getOrderedKeys();
+ HashMap<String, Pair<BubbleEntry, Boolean>> pendingOrActiveNotif = new HashMap<>();
+ for (int i = 0; i < orderedKeys.length; i++) {
+ String key = orderedKeys[i];
+ NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
+ BubbleEntry bubbleEntry = entry != null
+ ? notifToBubbleEntry(entry)
+ : null;
+ boolean shouldBubbleUp = entry != null
+ ? mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+ : false;
+ pendingOrActiveNotif.put(key, new Pair<>(bubbleEntry, shouldBubbleUp));
+ }
+ mBubbles.onRankingUpdated(rankingMap, pendingOrActiveNotif);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
index a52a598..0457100 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
@@ -19,7 +19,7 @@
import android.app.Activity;
import android.os.Bundle;
-import com.android.systemui.R;
+import com.android.systemui.tests.R;
/**
* Test activity for resolving {@link EmergencyGesture#ACTION_LAUNCH_EMERGENCY} action.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index b452d3a..1ec1da4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -98,7 +98,7 @@
mQSCarrierGroupController = new QSCarrierGroupController.Builder(
mActivityStarter, handler, TestableLooper.get(this).getLooper(),
- mNetworkController, mCarrierTextControllerBuilder)
+ mNetworkController, mCarrierTextControllerBuilder, mContext)
.setQSCarrierGroup(mQSCarrierGroup)
.build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
index bd37259..4c84df2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
@@ -34,7 +34,7 @@
linearLayout.setOrientation(LinearLayout.VERTICAL);
TextView text = new TextView(this);
text.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40);
- text.setText(com.android.systemui.R.string.test_content);
+ text.setText(com.android.systemui.tests.R.string.test_content);
linearLayout.addView(text);
scrollView.addView(linearLayout);
setContentView(scrollView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index d131dce..e16d4d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -36,16 +36,20 @@
import android.app.Notification;
import android.app.NotificationChannel;
+import android.os.Handler;
import android.os.UserHandle;
-import android.provider.Settings;
+import android.provider.DeviceConfig;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.util.Pair;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.util.DeviceConfigProxyFake;
import junit.framework.Assert;
@@ -55,38 +59,44 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class AssistantFeedbackControllerTest extends SysuiTestCase {
- private static final int ON = 1;
- private static final int OFF = 0;
private static final String TEST_PACKAGE_NAME = "test_package";
private static final int TEST_UID = 1;
private AssistantFeedbackController mAssistantFeedbackController;
+ private DeviceConfigProxyFake mProxyFake;
+ private TestableLooper mTestableLooper;
+
private StatusBarNotification mSbn;
@Before
public void setUp() {
- mAssistantFeedbackController = new AssistantFeedbackController(mContext);
- switchSetting(ON);
+ mProxyFake = new DeviceConfigProxyFake();
+ mTestableLooper = TestableLooper.get(this);
+ mAssistantFeedbackController = new AssistantFeedbackController(
+ new Handler(mTestableLooper.getLooper()),
+ mContext, mProxyFake);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, TEST_UID, 0, new Notification(),
UserHandle.CURRENT, null, 0);
}
@Test
- public void testUserControls_settingDisabled() {
- switchSetting(OFF);
+ public void testFlagDisabled() {
+ switchFlag("false");
assertFalse(mAssistantFeedbackController.isFeedbackEnabled());
}
@Test
- public void testUserControls_settingEnabled() {
+ public void testFlagEnabled() {
+ switchFlag("true");
assertTrue(mAssistantFeedbackController.isFeedbackEnabled());
}
@Test
- public void testFeedback_settingDisabled() {
- switchSetting(OFF);
+ public void testFeedback_flagDisabled() {
+ switchFlag("false");
assertEquals(STATUS_UNCHANGED, mAssistantFeedbackController.getFeedbackStatus(
getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
assertFalse(mAssistantFeedbackController.showFeedbackIndicator(
@@ -95,6 +105,7 @@
@Test
public void testFeedback_changedImportance() {
+ switchFlag("true");
NotificationEntry entry = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_UNCHANGED);
assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
assertTrue(mAssistantFeedbackController.showFeedbackIndicator(entry));
@@ -110,6 +121,7 @@
@Test
public void testFeedback_changedRanking() {
+ switchFlag("true");
NotificationEntry entry =
getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_PROMOTED);
assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
@@ -121,8 +133,8 @@
}
@Test
- public void testGetFeedbackResources_settingDisabled() {
- switchSetting(OFF);
+ public void testGetFeedbackResources_flagDisabled() {
+ switchFlag("false");
Assert.assertEquals(new Pair(0, 0), mAssistantFeedbackController.getFeedbackResources(
getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
}
@@ -138,9 +150,10 @@
.build();
}
- private void switchSetting(int setting) {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.NOTIFICATION_FEEDBACK_ENABLED, setting);
- mAssistantFeedbackController.update(null);
+ private void switchFlag(String enabled) {
+ mProxyFake.setProperty(
+ DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.ENABLE_NAS_FEEDBACK,
+ enabled, false);
+ mTestableLooper.processAllMessages();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
index 7eeae67..e6287e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
@@ -38,8 +38,8 @@
import androidx.palette.graphics.Palette;
import androidx.test.runner.AndroidJUnit4;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.tests.R;
import org.junit.After;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 6b0a23f..2e2945e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -50,7 +50,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -61,6 +60,7 @@
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.statusbar.policy.SmartRepliesAndActionsInflater;
+import com.android.systemui.tests.R;
import org.junit.Assert;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 6fcc7fa..64a7bee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -43,7 +43,6 @@
import android.view.LayoutInflater;
import android.widget.RemoteViews;
-import com.android.systemui.R;
import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.media.MediaFeatureFlag;
@@ -68,6 +67,7 @@
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
+import com.android.systemui.tests.R;
import com.android.systemui.wmshell.BubblesManager;
import com.android.systemui.wmshell.BubblesTestActivity;
import com.android.wm.shell.bubbles.Bubbles;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
index a147c8d..45f7c5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
@@ -24,10 +24,10 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
+import com.android.systemui.tests.R;
import org.junit.Assert;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index b9fd75e..fa253e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -35,7 +35,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
@@ -58,7 +57,6 @@
@Mock private PowerManager mPowerManager;
@Mock private TunerService mTunerService;
@Mock private BatteryController mBatteryController;
- @Mock private FeatureFlags mFeatureFlags;
@Before
public void setup() {
@@ -69,8 +67,7 @@
mAlwaysOnDisplayPolicy,
mPowerManager,
mBatteryController,
- mTunerService,
- mFeatureFlags
+ mTunerService
);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 253460d..cae488a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -97,7 +97,6 @@
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -259,7 +258,6 @@
@Mock private DemoModeController mDemoModeController;
@Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
- @Mock private FeatureFlags mFeatureFlags;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -420,8 +418,7 @@
mNotificationShadeDepthControllerLazy,
mStatusBarTouchableRegionManager,
mNotificationIconAreaController,
- mBrightnessSliderFactory,
- mFeatureFlags);
+ mBrightnessSliderFactory);
when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
mLockIconContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index c212cf3..67c1a08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -26,12 +26,12 @@
import androidx.test.runner.AndroidJUnit4;
-import com.android.settingslib.R;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.tests.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index f8b6383..89cc2b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -430,6 +430,10 @@
updateSignalStrength();
}
+ public void setImsType(int imsType) {
+ mMobileSignalController.setImsType(imsType);
+ }
+
public void setIsGsm(boolean gsm) {
when(mSignalStrength.isGsm()).thenReturn(gsm);
updateSignalStrength();
@@ -632,6 +636,14 @@
}
}
+ protected void verifyLastCallStrength(int icon) {
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
+ verify(mCallbackHandler, Mockito.atLeastOnce()).setCallIndicator(
+ iconArg.capture(),
+ anyInt());
+ assertEquals("Call strength, in status bar", icon, (int) iconArg.getValue().icon);
+ }
+
protected void assertNetworkNameEquals(String expected) {
assertEquals("Network name", expected, mMobileSignalController.getState().networkName);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 10166cb..fc1a08ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -15,6 +15,7 @@
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.telephony.CellSignalStrength;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -243,6 +244,28 @@
}
}
+ @Test
+ public void testCallStrengh() {
+ String testSsid = "Test SSID";
+ setWifiEnabled(true);
+ setWifiState(true, testSsid);
+ // Set the ImsType to be IMS_TYPE_WLAN
+ setImsType(2);
+ setWifiLevel(1);
+ for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
+ setWifiLevel(testLevel);
+ verifyLastCallStrength(TelephonyIcons.WIFI_CALL_STRENGTH_ICONS[testLevel]);
+ }
+ // Set the ImsType to be IMS_TYPE_WWAN
+ setImsType(1);
+ for (int testStrength = 0;
+ testStrength < CellSignalStrength.getNumSignalStrengthLevels(); testStrength++) {
+ setupDefaultSignal();
+ setLevel(testStrength);
+ verifyLastCallStrength(TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[testStrength]);
+ }
+ }
+
protected void setWifiActivity(int activity) {
// TODO: Not this, because this variable probably isn't sticking around.
mNetworkController.mWifiSignalController.setActivity(activity);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index c0af15b..203ece9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -19,8 +19,8 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import java.util.List;
@@ -66,7 +66,7 @@
}
@Override
- public void setNoCallingIcons(String slot, List<NoCallingIconState> states) {
+ public void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states) {
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
index f4d96a12..ab329c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
@@ -20,7 +20,7 @@
import android.content.Intent;
import android.os.Bundle;
-import com.android.systemui.R;
+import com.android.systemui.tests.R;
/**
* Referenced by NotificationTestHelper#makeBubbleMetadata
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 38275f7..6c30999 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1245,9 +1245,10 @@
@Override
public IRestoreSession beginRestoreSessionForUser(
- int userId, String packageName, String transportID) throws RemoteException {
+ int userId, String packageName, String transportID,
+ @OperationType int operationType) throws RemoteException {
return isUserReadyForBackup(userId)
- ? beginRestoreSession(userId, packageName, transportID) : null;
+ ? beginRestoreSession(userId, packageName, transportID, operationType) : null;
}
/**
@@ -1256,13 +1257,15 @@
*/
@Nullable
public IRestoreSession beginRestoreSession(
- @UserIdInt int userId, String packageName, String transportName) {
+ @UserIdInt int userId, String packageName, String transportName,
+ @OperationType int operationType) {
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
return userBackupManagerService == null
? null
- : userBackupManagerService.beginRestoreSession(packageName, transportName);
+ : userBackupManagerService.beginRestoreSession(packageName, transportName,
+ operationType);
}
@Override
@@ -1347,15 +1350,15 @@
if (!isUserReadyForBackup(userId)) {
return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
}
- return requestBackup(userId, packages, observer, monitor, flags);
+ return requestBackup(userId, packages, observer, monitor, flags, OperationType.BACKUP);
}
@Override
public int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags)
+ IBackupManagerMonitor monitor, int flags, @OperationType int operationType)
throws RemoteException {
return requestBackup(binderGetCallingUserId(), packages,
- observer, monitor, flags);
+ observer, monitor, flags, operationType);
}
/**
@@ -1367,13 +1370,15 @@
String[] packages,
IBackupObserver observer,
IBackupManagerMonitor monitor,
- int flags) {
+ int flags,
+ @OperationType int operationType) {
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(userId, "requestBackup()");
return userBackupManagerService == null
? BackupManager.ERROR_BACKUP_NOT_ALLOWED
- : userBackupManagerService.requestBackup(packages, observer, monitor, flags);
+ : userBackupManagerService.requestBackup(packages, observer, monitor, flags,
+ operationType);
}
@Override
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index faec95f..136cd22f 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -127,7 +127,6 @@
import com.android.server.backup.restore.ActiveRestoreSession;
import com.android.server.backup.restore.PerformUnifiedRestoreTask;
import com.android.server.backup.transport.TransportClient;
-import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
@@ -1861,10 +1860,19 @@
/**
* Requests a backup for the inputted {@code packages} with a specified {@link
- * IBackupManagerMonitor} and {@link OperationType}.
+ * IBackupManagerMonitor}.
*/
public int requestBackup(String[] packages, IBackupObserver observer,
IBackupManagerMonitor monitor, int flags) {
+ return requestBackup(packages, observer, monitor, flags, OperationType.BACKUP);
+ }
+
+ /**
+ * Requests a backup for the inputted {@code packages} with a specified {@link
+ * IBackupManagerMonitor} and {@link OperationType}.
+ */
+ public int requestBackup(String[] packages, IBackupObserver observer,
+ IBackupManagerMonitor monitor, int flags, @OperationType int operationType) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
if (packages == null || packages.length < 1) {
@@ -1895,16 +1903,13 @@
final TransportClient transportClient;
final String transportDirName;
- int operationType;
try {
transportDirName =
mTransportManager.getTransportDirName(
mTransportManager.getCurrentTransportName());
transportClient =
mTransportManager.getCurrentTransportClientOrThrow("BMS.requestBackup()");
- operationType = getOperationTypeFromTransport(transportClient);
- } catch (TransportNotRegisteredException | TransportNotAvailableException
- | RemoteException e) {
+ } catch (TransportNotRegisteredException e) {
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
@@ -4019,13 +4024,15 @@
}
/** Hand off a restore session. */
- public IRestoreSession beginRestoreSession(String packageName, String transport) {
+ public IRestoreSession beginRestoreSession(String packageName, String transport,
+ @OperationType int operationType) {
if (DEBUG) {
Slog.v(
TAG,
addUserIdToLogMessage(
mUserId,
- "beginRestoreSession: pkg=" + packageName + " transport=" + transport));
+ "beginRestoreSession: pkg=" + packageName + " transport=" + transport
+ + "operationType=" + operationType));
}
boolean needPermission = true;
@@ -4066,17 +4073,6 @@
}
}
- int operationType;
- try {
- operationType = getOperationTypeFromTransport(
- mTransportManager.getTransportClientOrThrow(transport, /* caller */
- "BMS.beginRestoreSession"));
- } catch (TransportNotAvailableException | TransportNotRegisteredException
- | RemoteException e) {
- Slog.w(TAG, "Failed to get operation type from transport: " + e);
- return null;
- }
-
synchronized (this) {
if (mActiveRestoreSession != null) {
Slog.i(
@@ -4360,23 +4356,6 @@
}
}
- @VisibleForTesting
- @OperationType int getOperationTypeFromTransport(TransportClient transportClient)
- throws TransportNotAvailableException, RemoteException {
- long oldCallingId = Binder.clearCallingIdentity();
- try {
- IBackupTransport transport = transportClient.connectOrThrow(
- /* caller */ "BMS.getOperationTypeFromTransport");
- if ((transport.getTransportFlags() & BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
- return OperationType.MIGRATION;
- } else {
- return OperationType.BACKUP;
- }
- } finally {
- Binder.restoreCallingIdentity(oldCallingId);
- }
- }
-
private static String addUserIdToLogMessage(int userId, String message) {
return "[UserID:" + userId + "] " + message;
}
diff --git a/services/core/java/com/android/server/accounts/OWNERS b/services/core/java/com/android/server/accounts/OWNERS
index ea5fd36..8dcc04a 100644
--- a/services/core/java/com/android/server/accounts/OWNERS
+++ b/services/core/java/com/android/server/accounts/OWNERS
@@ -3,7 +3,6 @@
sandrakwan@google.com
hackbod@google.com
svetoslavganov@google.com
-moltmann@google.com
fkupolov@google.com
yamasani@google.com
omakoto@google.com
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f0f29a9..bedd19b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1490,7 +1490,9 @@
private static final int INDEX_TOTAL_SWAP_PSS = 10;
private static final int INDEX_TOTAL_RSS = 11;
private static final int INDEX_TOTAL_NATIVE_PSS = 12;
- private static final int INDEX_LAST = 13;
+ private static final int INDEX_TOTAL_MEMTRACK_GRAPHICS = 13;
+ private static final int INDEX_TOTAL_MEMTRACK_GL = 14;
+ private static final int INDEX_LAST = 15;
final class UiHandler extends Handler {
public UiHandler() {
@@ -10316,6 +10318,7 @@
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscRss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+ long[] memtrackTmp = new long[4];
long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
@@ -10349,6 +10352,8 @@
final int reportType;
final long startTime;
final long endTime;
+ long memtrackGraphics = 0;
+ long memtrackGl = 0;
if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
reportType = ProcessStats.ADD_PSS_EXTERNAL_SLOW;
startTime = SystemClock.currentThreadTimeMillis();
@@ -10360,7 +10365,7 @@
} else {
reportType = ProcessStats.ADD_PSS_EXTERNAL;
startTime = SystemClock.currentThreadTimeMillis();
- long pss = Debug.getPss(pid, tmpLong, null);
+ long pss = Debug.getPss(pid, tmpLong, memtrackTmp);
if (pss == 0) {
continue;
}
@@ -10368,6 +10373,8 @@
endTime = SystemClock.currentThreadTimeMillis();
mi.dalvikPrivateDirty = (int) tmpLong[0];
mi.dalvikRss = (int) tmpLong[2];
+ memtrackGraphics = memtrackTmp[1];
+ memtrackGl = memtrackTmp[2];
}
if (!opts.isCheckinRequest && opts.dumpDetails) {
pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
@@ -10431,6 +10438,8 @@
ss[INDEX_TOTAL_PSS] += myTotalPss;
ss[INDEX_TOTAL_SWAP_PSS] += myTotalSwapPss;
ss[INDEX_TOTAL_RSS] += myTotalRss;
+ ss[INDEX_TOTAL_MEMTRACK_GRAPHICS] += memtrackGraphics;
+ ss[INDEX_TOTAL_MEMTRACK_GL] += memtrackGl;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
(hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
myTotalSwapPss, myTotalRss, pid, hasActivities);
@@ -10494,6 +10503,8 @@
final Debug.MemoryInfo[] memInfos = new Debug.MemoryInfo[1];
mAppProfiler.forAllCpuStats((st) -> {
if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+ long memtrackGraphics = 0;
+ long memtrackGl = 0;
if (memInfos[0] == null) {
memInfos[0] = new Debug.MemoryInfo();
}
@@ -10503,13 +10514,15 @@
return;
}
} else {
- long pss = Debug.getPss(st.pid, tmpLong, null);
+ long pss = Debug.getPss(st.pid, tmpLong, memtrackTmp);
if (pss == 0) {
return;
}
info.nativePss = (int) pss;
info.nativePrivateDirty = (int) tmpLong[0];
info.nativeRss = (int) tmpLong[2];
+ memtrackGraphics = memtrackTmp[1];
+ memtrackGl = memtrackTmp[2];
}
final long myTotalPss = info.getTotalPss();
@@ -10519,6 +10532,8 @@
ss[INDEX_TOTAL_SWAP_PSS] += myTotalSwapPss;
ss[INDEX_TOTAL_RSS] += myTotalRss;
ss[INDEX_TOTAL_NATIVE_PSS] += myTotalPss;
+ ss[INDEX_TOTAL_MEMTRACK_GRAPHICS] += memtrackGraphics;
+ ss[INDEX_TOTAL_MEMTRACK_GL] += memtrackGl;
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
st.name, myTotalPss, info.getSummaryTotalSwapPss(), myTotalRss,
@@ -10726,7 +10741,11 @@
pw.print(" mapped + ");
pw.print(stringifyKBSize(dmabufUnmapped));
pw.println(" unmapped)");
- kernelUsed += totalExportedDmabuf;
+ // Account unmapped dmabufs as part of kernel memory allocations
+ kernelUsed += dmabufUnmapped;
+ // Replace memtrack HAL reported Graphics category with mapped dmabufs
+ ss[INDEX_TOTAL_PSS] -= ss[INDEX_TOTAL_MEMTRACK_GRAPHICS];
+ ss[INDEX_TOTAL_PSS] += dmabufMapped;
}
final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
if (totalDmabufHeapPool >= 0) {
@@ -10736,13 +10755,27 @@
}
final long gpuUsage = Debug.getGpuTotalUsageKb();
if (gpuUsage >= 0) {
- pw.print(" GPU: "); pw.println(stringifyKBSize(gpuUsage));
+ final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
+ if (gpuDmaBufUsage >= 0) {
+ final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+ pw.print(" GPU: ");
+ pw.print(stringifyKBSize(gpuUsage));
+ pw.print(" (");
+ pw.print(stringifyKBSize(gpuDmaBufUsage));
+ pw.print(" dmabuf + ");
+ pw.print(stringifyKBSize(gpuPrivateUsage));
+ pw.println(" private)");
+ // Replace memtrack HAL reported GL category with private GPU allocations and
+ // account it as part of kernel memory allocations
+ ss[INDEX_TOTAL_PSS] -= ss[INDEX_TOTAL_MEMTRACK_GL];
+ kernelUsed += gpuPrivateUsage;
+ } else {
+ pw.print(" GPU: "); pw.println(stringifyKBSize(gpuUsage));
+ }
}
- /*
- * Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
- * memInfo.getCachedSizeKb().
- */
+ // Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
+ // memInfo.getCachedSizeKb().
final long lostRAM = memInfo.getTotalSizeKb()
- (ss[INDEX_TOTAL_PSS] - ss[INDEX_TOTAL_SWAP_PSS])
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 3ff5872..fc7a476 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1322,7 +1322,7 @@
infoMap.put(mi.pid, mi);
}
updateCpuStatsNow();
- long[] memtrackTmp = new long[1];
+ long[] memtrackTmp = new long[4];
long[] swaptrackTmp = new long[2];
// Get a list of Stats that have vsize > 0
final List<ProcessCpuTracker.Stats> stats = getCpuStats(st -> st.vsize > 0);
@@ -1345,6 +1345,8 @@
long totalPss = 0;
long totalSwapPss = 0;
long totalMemtrack = 0;
+ long totalMemtrackGraphics = 0;
+ long totalMemtrackGl = 0;
for (int i = 0, size = memInfos.size(); i < size; i++) {
ProcessMemInfo mi = memInfos.get(i);
if (mi.pss == 0) {
@@ -1355,6 +1357,8 @@
totalPss += mi.pss;
totalSwapPss += mi.swapPss;
totalMemtrack += mi.memtrack;
+ totalMemtrackGraphics += memtrackTmp[1];
+ totalMemtrackGl += memtrackTmp[2];
}
Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
@Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
@@ -1521,10 +1525,16 @@
} else {
final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
if (totalExportedDmabuf >= 0) {
+ final long dmabufMapped = Debug.getDmabufMappedSizeKb();
+ final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;
memInfoBuilder.append("DMA-BUF: ");
memInfoBuilder.append(stringifyKBSize(totalExportedDmabuf));
memInfoBuilder.append("\n");
- kernelUsed += totalExportedDmabuf;
+ // Account unmapped dmabufs as part of kernel memory allocations
+ kernelUsed += dmabufUnmapped;
+ // Replace memtrack HAL reported Graphics category with mapped dmabufs
+ totalPss -= totalMemtrackGraphics;
+ totalPss += dmabufMapped;
}
final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
@@ -1537,19 +1547,34 @@
final long gpuUsage = Debug.getGpuTotalUsageKb();
if (gpuUsage >= 0) {
- memInfoBuilder.append(" GPU: ");
- memInfoBuilder.append(stringifyKBSize(gpuUsage));
- memInfoBuilder.append("\n");
+ final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
+ if (gpuDmaBufUsage >= 0) {
+ final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+ memInfoBuilder.append(" GPU: ");
+ memInfoBuilder.append(stringifyKBSize(gpuUsage));
+ memInfoBuilder.append(" (");
+ memInfoBuilder.append(stringifyKBSize(gpuDmaBufUsage));
+ memInfoBuilder.append(" dmabuf + ");
+ memInfoBuilder.append(stringifyKBSize(gpuPrivateUsage));
+ memInfoBuilder.append(" private)\n");
+ // Replace memtrack HAL reported GL category with private GPU allocations and
+ // account it as part of kernel memory allocations
+ totalPss -= totalMemtrackGl;
+ kernelUsed += gpuPrivateUsage;
+ } else {
+ memInfoBuilder.append(" GPU: ");
+ memInfoBuilder.append(stringifyKBSize(gpuUsage));
+ memInfoBuilder.append("\n");
+ }
+
}
memInfoBuilder.append(" Used RAM: ");
memInfoBuilder.append(stringifyKBSize(
totalPss - cachedPss + kernelUsed));
memInfoBuilder.append("\n");
- /*
- * Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
- * memInfo.getCachedSizeKb().
- */
+ // Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
+ // memInfo.getCachedSizeKb().
memInfoBuilder.append(" Lost RAM: ");
memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb()
- (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 87b4c16..7ef315c 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -27,7 +27,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.util.CollectionUtils;
import com.android.server.ConnectivityService;
@@ -260,18 +260,18 @@
}
private static void log(final String msg) {
- Slog.d(TAG, msg);
+ Log.d(TAG, msg);
}
private static void logw(final String msg) {
- Slog.w(TAG, msg);
+ Log.w(TAG, msg);
}
private static void loge(final String msg) {
- Slog.e(TAG, msg);
+ Log.e(TAG, msg);
}
private static void logwtf(final String msg) {
- Slog.wtf(TAG, msg);
+ Log.wtf(TAG, msg);
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index cb9793f..685e9e6 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -279,6 +279,7 @@
super.onBootPhase(phase);
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mLockSettingsService.migrateOldDataAfterSystemReady();
+ mLockSettingsService.loadEscrowData();
}
}
@@ -824,13 +825,17 @@
mSpManager.initWeaverService();
getAuthSecretHal();
mDeviceProvisionedObserver.onSystemReady();
- mRebootEscrowManager.loadRebootEscrowDataIfAvailable();
+
// TODO: maybe skip this for split system user mode.
mStorage.prefetchUser(UserHandle.USER_SYSTEM);
mBiometricDeferredQueue.systemReady(mInjector.getFingerprintManager(),
mInjector.getFaceManager());
}
+ private void loadEscrowData() {
+ mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler);
+ }
+
private void getAuthSecretHal() {
try {
mAuthSecretService = IAuthSecret.getService(/* retry */ true);
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 06962d4..53b62ca 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -21,6 +21,7 @@
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.os.Handler;
import android.os.SystemClock;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -39,6 +40,7 @@
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import javax.crypto.SecretKey;
@@ -76,6 +78,13 @@
private static final int BOOT_COUNT_TOLERANCE = 5;
/**
+ * The default retry specs for loading reboot escrow data. We will attempt to retry loading
+ * escrow data on temporarily errors, e.g. unavailable network.
+ */
+ private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
+ private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
+
+ /**
* Logs events for later debugging in bugreports.
*/
private final RebootEscrowEventLog mEventLog;
@@ -148,6 +157,14 @@
return null;
}
+ void post(Handler handler, Runnable runnable) {
+ handler.post(runnable);
+ }
+
+ void postDelayed(Handler handler, Runnable runnable, long delayMillis) {
+ handler.postDelayed(runnable, delayMillis);
+ }
+
public Context getContext() {
return mContext;
}
@@ -199,7 +216,18 @@
mKeyStoreManager = injector.getKeyStoreManager();
}
- void loadRebootEscrowDataIfAvailable() {
+ private void onGetRebootEscrowKeyFailed(List<UserInfo> users) {
+ Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
+ for (UserInfo user : users) {
+ mStorage.removeRebootEscrow(user.id);
+ }
+
+ // Clear the old key in keystore.
+ mKeyStoreManager.clearKeyStoreEncryptionKey();
+ onEscrowRestoreComplete(false);
+ }
+
+ void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
List<UserInfo> users = mUserManager.getUsers();
List<UserInfo> rebootEscrowUsers = new ArrayList<>();
for (UserInfo user : users) {
@@ -212,17 +240,49 @@
return;
}
+ mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry(
+ retryHandler, 0, users, rebootEscrowUsers));
+ }
+
+ void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber,
+ List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+ Objects.requireNonNull(retryHandler);
+
+ final int retryLimit = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+ "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
+ final int retryIntervalInSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+ "load_escrow_data_retry_interval_seconds",
+ DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
+
+ if (attemptNumber < retryLimit) {
+ Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
+ mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry(
+ retryHandler, attemptNumber, users, rebootEscrowUsers),
+ retryIntervalInSeconds * 1000);
+ return;
+ }
+
+ Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
+ onGetRebootEscrowKeyFailed(users);
+ }
+
+ void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
+ List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
// Fetch the key from keystore to decrypt the escrow data & escrow key; this key is
// generated before reboot. Note that we will clear the escrow key even if the keystore key
// is null.
SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
- RebootEscrowKey escrowKey = getAndClearRebootEscrowKey(kk);
+ RebootEscrowKey escrowKey;
+ try {
+ escrowKey = getAndClearRebootEscrowKey(kk);
+ } catch (IOException e) {
+ scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users,
+ rebootEscrowUsers);
+ return;
+ }
+
if (kk == null || escrowKey == null) {
- Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
- for (UserInfo user : users) {
- mStorage.removeRebootEscrow(user.id);
- }
- onEscrowRestoreComplete(false);
+ onGetRebootEscrowKeyFailed(users);
return;
}
@@ -249,7 +309,7 @@
}
}
- private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) {
+ private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) {
Slog.w(TAG,
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
index 6c1040b..4b00772 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
@@ -33,7 +33,7 @@
* An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL.
*/
class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface {
- private static final String TAG = "RebootEscrowProvider";
+ private static final String TAG = "RebootEscrowProviderHal";
private final Injector mInjector;
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
index 857ad5f..af6faad 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
@@ -16,6 +16,8 @@
package com.android.server.locksettings;
+import java.io.IOException;
+
import javax.crypto.SecretKey;
/**
@@ -33,9 +35,10 @@
/**
* Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted,
- * use the input key to decrypt the RebootEscrowKey. Returns null on failure.
+ * use the input key to decrypt the RebootEscrowKey. Returns null on failure. Throws an
+ * IOException if the failure is non-fatal, and a retry may succeed.
*/
- RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey);
+ RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException;
/**
* Clears the stored RebootEscrowKey.
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
index ba1a680..9d09637 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -35,7 +35,7 @@
* encrypt & decrypt the blob.
*/
class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterface {
- private static final String TAG = "RebootEscrowProvider";
+ private static final String TAG = "RebootEscrowProviderServerBased";
// Timeout for service binding
private static final long DEFAULT_SERVICE_TIMEOUT_IN_SECONDS = 10;
@@ -50,6 +50,8 @@
private final Injector mInjector;
+ private byte[] mServerBlob;
+
static class Injector {
private ResumeOnRebootServiceConnection mServiceConnection = null;
@@ -124,17 +126,20 @@
}
@Override
- public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) {
- byte[] serverBlob = mStorage.readRebootEscrowServerBlob();
+ public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException {
+ if (mServerBlob == null) {
+ mServerBlob = mStorage.readRebootEscrowServerBlob();
+ }
// Delete the server blob in storage.
mStorage.removeRebootEscrowServerBlob();
- if (serverBlob == null) {
+ if (mServerBlob == null) {
Slog.w(TAG, "Failed to read reboot escrow server blob from storage");
return null;
}
+ Slog.i(TAG, "Loaded reboot escrow server blob from storage");
try {
- byte[] escrowKeyBytes = unwrapServerBlob(serverBlob, decryptionKey);
+ byte[] escrowKeyBytes = unwrapServerBlob(mServerBlob, decryptionKey);
if (escrowKeyBytes == null) {
Slog.w(TAG, "Decrypted reboot escrow key bytes should not be null");
return null;
@@ -145,7 +150,7 @@
}
return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
- } catch (TimeoutException | RemoteException | IOException e) {
+ } catch (TimeoutException | RemoteException e) {
Slog.w(TAG, "Failed to decrypt the server blob ", e);
return null;
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 769b781..78c1a95 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.IPackageManager;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.IBinder;
import android.os.IInterface;
@@ -197,6 +198,11 @@
}
@Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+ // nothing to filter
+ }
+
+ @Override
protected void loadDefaultsFromConfig() {
String defaultDndAccess = mContext.getResources().getString(
R.string.config_defaultDndAccessPackages);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 21537e6..bbdcac2 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -189,6 +189,8 @@
abstract protected void onServiceAdded(ManagedServiceInfo info);
+ abstract protected void ensureFilters(ServiceInfo si, int userId);
+
protected List<ManagedServiceInfo> getServices() {
synchronized (mMutex) {
List<ManagedServiceInfo> services = new ArrayList<>(mServices);
@@ -1342,8 +1344,10 @@
for (ComponentName component : add) {
try {
ServiceInfo info = mPm.getServiceInfo(component,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
if (info == null) {
Slog.w(TAG, "Not binding " + getCaption() + " service " + component
+ ": service not found");
@@ -1356,7 +1360,7 @@
}
Slog.v(TAG,
"enabling " + getCaption() + " for " + userId + ": " + component);
- registerService(component, userId);
+ registerService(info, userId);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -1368,9 +1372,15 @@
* Version of registerService that takes the name of a service component to bind to.
*/
@VisibleForTesting
- void registerService(final ComponentName name, final int userid) {
+ void registerService(final ServiceInfo si, final int userId) {
+ ensureFilters(si, userId);
+ registerService(si.getComponentName(), userId);
+ }
+
+ @VisibleForTesting
+ void registerService(final ComponentName cn, final int userId) {
synchronized (mMutex) {
- registerServiceLocked(name, userid);
+ registerServiceLocked(cn, userId);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5703ffe..917be29 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -177,6 +177,7 @@
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.UserInfo;
+import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.media.AudioAttributes;
@@ -214,6 +215,7 @@
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
@@ -8969,7 +8971,8 @@
NotificationListenerFilter nls = mListeners.getNotificationListenerFilter(listener.mKey);
if (nls != null
&& (!nls.isTypeAllowed(notificationType)
- || !nls.isPackageAllowed(sbn.getPackageName()))) {
+ || !nls.isPackageAllowed(
+ new VersionedPackage(sbn.getPackageName(), sbn.getUid())))) {
return false;
}
return true;
@@ -9132,6 +9135,12 @@
}
@Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+ // nothing to filter; no user visible settings for types/packages like other
+ // listeners
+ }
+
+ @Override
@GuardedBy("mNotificationLock")
protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
mListeners.unregisterService(removed.service, removed.userid);
@@ -9576,11 +9585,12 @@
public class NotificationListeners extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
- static final String TAG_REQUESTED_LISTENERS = "req_listeners";
+ static final String TAG_REQUESTED_LISTENERS = "request_listeners";
static final String TAG_REQUESTED_LISTENER = "listener";
static final String ATT_COMPONENT = "component";
static final String ATT_TYPES = "types";
- static final String ATT_PKGS = "pkgs";
+ static final String ATT_PKG = "pkg";
+ static final String ATT_UID = "uid";
static final String TAG_APPROVED = "allowed";
static final String TAG_DISALLOWED= "disallowed";
static final String XML_SEPARATOR = ",";
@@ -9698,28 +9708,6 @@
}
@Override
- public void onUserUnlocked(int user) {
- int flags = PackageManager.GET_SERVICES | PackageManager.GET_META_DATA;
-
- final PackageManager pmWrapper = mContext.getPackageManager();
- List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser(
- new Intent(getConfig().serviceInterface), flags, user);
-
- for (ResolveInfo resolveInfo : installedServices) {
- ServiceInfo info = resolveInfo.serviceInfo;
-
- if (!getConfig().bindPermission.equals(info.permission)) {
- continue;
- }
- Pair key = Pair.create(info.getComponentName(), user);
- if (!mRequestedNotificationListeners.containsKey(key)) {
- mRequestedNotificationListeners.put(key, new NotificationListenerFilter());
- }
- }
- super.onUserUnlocked(user);
- }
-
- @Override
public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
super.onPackagesChanged(removingPackage, pkgList, uidList);
@@ -9738,6 +9726,18 @@
}
}
}
+
+ // clean up anything in the disallowed pkgs list
+ for (int i = 0; i < pkgList.length; i++) {
+ String pkg = pkgList[i];
+ int userId = UserHandle.getUserId(uidList[i]);
+ for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
+ NotificationListenerFilter nlf = mRequestedNotificationListeners.valueAt(j);
+
+ VersionedPackage ai = new VersionedPackage(pkg, uidList[i]);
+ nlf.removePackage(ai);
+ }
+ }
}
@Override
@@ -9767,15 +9767,17 @@
int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING
| FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING;
- ArraySet<String> disallowedPkgs = new ArraySet<>();
+ ArraySet<VersionedPackage> disallowedPkgs = new ArraySet<>();
final int listenerOuterDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, listenerOuterDepth)) {
if (TAG_APPROVED.equals(parser.getName())) {
approved = XmlUtils.readIntAttribute(parser, ATT_TYPES);
} else if (TAG_DISALLOWED.equals(parser.getName())) {
- String pkgs = XmlUtils.readStringAttribute(parser, ATT_PKGS);
- if (!TextUtils.isEmpty(pkgs)) {
- disallowedPkgs = new ArraySet<>(pkgs.split(XML_SEPARATOR));
+ String pkg = XmlUtils.readStringAttribute(parser, ATT_PKG);
+ int uid = XmlUtils.readIntAttribute(parser, ATT_UID);
+ if (!TextUtils.isEmpty(pkg)) {
+ VersionedPackage ai = new VersionedPackage(pkg, uid);
+ disallowedPkgs.add(ai);
}
}
}
@@ -9800,10 +9802,14 @@
XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes());
out.endTag(null, TAG_APPROVED);
- out.startTag(null, TAG_DISALLOWED);
- XmlUtils.writeStringAttribute(
- out, ATT_PKGS, String.join(XML_SEPARATOR, nlf.getDisallowedPackages()));
- out.endTag(null, TAG_DISALLOWED);
+ for (VersionedPackage ai : nlf.getDisallowedPackages()) {
+ if (!TextUtils.isEmpty(ai.getPackageName())) {
+ out.startTag(null, TAG_DISALLOWED);
+ XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName());
+ XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode());
+ out.endTag(null, TAG_DISALLOWED);
+ }
+ }
out.endTag(null, TAG_REQUESTED_LISTENER);
}
@@ -9821,6 +9827,38 @@
mRequestedNotificationListeners.put(pair, nlf);
}
+ @Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+ Pair listener = Pair.create(si.getComponentName(), userId);
+ NotificationListenerFilter existingNlf =
+ mRequestedNotificationListeners.get(listener);
+ if (existingNlf == null) {
+ // no stored filters for this listener; see if they provided a default
+ if (si.metaData != null) {
+ String typeList = si.metaData.getString(
+ NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES);
+ if (typeList != null) {
+ int types = 0;
+ String[] typeStrings = typeList.split(XML_SEPARATOR);
+ for (int i = 0; i < typeStrings.length; i++) {
+ if (TextUtils.isEmpty(typeStrings[i])) {
+ continue;
+ }
+ try {
+ types |= Integer.parseInt(typeStrings[i]);
+ } catch (NumberFormatException e) {
+ // skip
+ }
+ }
+
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(types, new ArraySet<>());
+ mRequestedNotificationListeners.put(listener, nlf);
+ }
+ }
+ }
+ }
+
@GuardedBy("mNotificationLock")
public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
if (trim == TRIM_LIGHT) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index b7b72d1..663fdee 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -335,6 +335,7 @@
final List<OverlayInfo> overlaysForTarget =
mInterface.getOverlayInfosForTarget(overlayInfo.targetPackageName, userId);
+ overlaysForTarget.remove(overlayInfo);
final OverlayManagerTransaction.Builder builder = new OverlayManagerTransaction.Builder();
for (final OverlayInfo disableOverlay : overlaysForTarget) {
if ((inCategory && !Objects.equals(disableOverlay.category,overlayInfo.category))
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index de85d9e..f31d1da 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -43,6 +43,7 @@
import android.util.ArraySet;
import android.util.Singleton;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -226,6 +227,12 @@
abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
/**
+ * Returns array of all staged sessions known to apexd.
+ */
+ @NonNull
+ abstract SparseArray<ApexSessionInfo> getSessions();
+
+ /**
* Submit a staged session to apex service. This causes the apex service to perform some initial
* verification and accept or reject the session. Submitting a session successfully is not
* enough for it to be activated at the next boot, the caller needs to call
@@ -691,6 +698,21 @@
}
@Override
+ SparseArray<ApexSessionInfo> getSessions() {
+ try {
+ final ApexSessionInfo[] sessions = waitForApexService().getSessions();
+ final SparseArray<ApexSessionInfo> result = new SparseArray<>(sessions.length);
+ for (int i = 0; i < sessions.length; i++) {
+ result.put(sessions[i].sessionId, sessions[i]);
+ }
+ return result;
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ }
+ }
+
+ @Override
ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException {
try {
final ApexInfoList apexInfoList = new ApexInfoList();
@@ -1083,6 +1105,11 @@
}
@Override
+ SparseArray<ApexSessionInfo> getSessions() {
+ return new SparseArray<>(0);
+ }
+
+ @Override
ApexInfoList submitStagedSession(ApexSessionParams params)
throws PackageManagerException {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2d393c0..2812830 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -295,23 +295,29 @@
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- if (session.isStaged()) {
- stagedSessionsToRestore.add(session.mStagedSession);
+ if (!session.isStaged()) {
+ continue;
+ }
+ StagingManager.StagedSession stagedSession = session.mStagedSession;
+ if (!stagedSession.isInTerminalState() && stagedSession.hasParentSessionId()
+ && getSession(stagedSession.getParentSessionId()) == null) {
+ stagedSession.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+ "An orphan staged session " + stagedSession.sessionId() + " is found, "
+ + "parent " + stagedSession.getParentSessionId() + " is missing");
+ continue;
+ }
+ if (!stagedSession.hasParentSessionId() && stagedSession.isCommitted()
+ && !stagedSession.isInTerminalState()) {
+ // StagingManager.restoreSessions expects a list of committed, non-finalized
+ // parent staged sessions.
+ stagedSessionsToRestore.add(stagedSession);
}
}
}
- // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK
+ // Don't hold mSessions lock when calling restoreSessions, since it might trigger an APK
// atomic install which needs to query sessions, which requires lock on mSessions.
- boolean isDeviceUpgrading = mPm.isDeviceUpgrading();
- for (StagingManager.StagedSession session : stagedSessionsToRestore) {
- if (!session.isInTerminalState() && session.hasParentSessionId()
- && getSession(session.getParentSessionId()) == null) {
- session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "An orphan staged session " + session.sessionId() + " is found, "
- + "parent " + session.getParentSessionId() + " is missing");
- }
- mStagingManager.restoreSession(session, isDeviceUpgrading);
- }
+ // Note: restoreSessions mutates content of stagedSessionsToRestore.
+ mStagingManager.restoreSessions(stagedSessionsToRestore, mPm.isDeviceUpgrading());
}
@GuardedBy("mSessions")
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 545567c..0a74032 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -50,8 +50,6 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IntArray;
@@ -63,6 +61,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageHelper;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
@@ -143,10 +142,16 @@
}
StagingManager(Context context, Supplier<PackageParser2> packageParserSupplier) {
+ this(context, packageParserSupplier, ApexManager.getInstance());
+ }
+
+ @VisibleForTesting
+ StagingManager(Context context, Supplier<PackageParser2> packageParserSupplier,
+ ApexManager apexManager) {
mContext = context;
mPackageParserSupplier = packageParserSupplier;
- mApexManager = ApexManager.getInstance();
+ mApexManager = apexManager;
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPreRebootVerificationHandler = new PreRebootVerificationHandler(
BackgroundThread.get().getLooper());
@@ -354,11 +359,11 @@
}
// Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
- private void abortCheckpoint(int sessionId, String errorMsg) {
- String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
+ private void abortCheckpoint(String failureReason, boolean supportsCheckpoint,
+ boolean needsCheckpoint) {
Slog.e(TAG, failureReason);
try {
- if (supportsCheckpoint() && needsCheckpoint()) {
+ if (supportsCheckpoint && needsCheckpoint) {
// Store failure reason for next reboot
try (BufferedWriter writer =
new BufferedWriter(new FileWriter(mFailureReasonFile))) {
@@ -371,8 +376,9 @@
if (mApexManager.isApexSupported()) {
mApexManager.revertActiveSessions();
}
+
PackageHelper.getStorageManager().abortChanges(
- "StagingManager initiated", false /*retry*/);
+ "abort-staged-install", false /*retry*/);
}
} catch (Exception e) {
Slog.wtf(TAG, "Failed to abort checkpoint", e);
@@ -384,14 +390,6 @@
}
}
- private boolean supportsCheckpoint() throws RemoteException {
- return PackageHelper.getStorageManager().supportsCheckpoint();
- }
-
- private boolean needsCheckpoint() throws RemoteException {
- return PackageHelper.getStorageManager().needsCheckpoint();
- }
-
/**
* Utility function for extracting apex sessions out of multi-package/single session.
*/
@@ -517,96 +515,31 @@
}
}
- private void resumeSession(@NonNull StagedSession session)
- throws PackageManagerException {
+ private void resumeSession(@NonNull StagedSession session, boolean supportsCheckpoint,
+ boolean needsCheckpoint) throws PackageManagerException {
Slog.d(TAG, "Resuming session " + session.sessionId());
final boolean hasApex = session.containsApexSession();
- ApexSessionInfo apexSessionInfo = null;
- if (hasApex) {
- // Check with apexservice whether the apex packages have been activated.
- apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId());
-
- // Prepare for logging a native crash during boot, if one occurred.
- if (apexSessionInfo != null && !TextUtils.isEmpty(
- apexSessionInfo.crashingNativeProcess)) {
- prepareForLoggingApexdRevert(session, apexSessionInfo.crashingNativeProcess);
- }
-
- if (apexSessionInfo != null && apexSessionInfo.isVerified) {
- // Session has been previously submitted to apexd, but didn't complete all the
- // pre-reboot verification, perhaps because the device rebooted in the meantime.
- // Greedily re-trigger the pre-reboot verification. We want to avoid marking it as
- // failed when not in checkpoint mode, hence it is being processed separately.
- Slog.d(TAG, "Found pending staged session " + session.sessionId() + " still to "
- + "be verified, resuming pre-reboot verification");
- mPreRebootVerificationHandler.startPreRebootVerification(session);
- return;
- }
- }
// Before we resume session, we check if revert is needed or not. Typically, we enter file-
// system checkpoint mode when we reboot first time in order to install staged sessions. We
// want to install staged sessions in this mode as rebooting now will revert user data. If
// something goes wrong, then we reboot again to enter fs-rollback mode. Rebooting now will
// have no effect on user data, so mark the sessions as failed instead.
- try {
- // If checkpoint is supported, then we only resume sessions if we are in checkpointing
- // mode. If not, we fail all sessions.
- if (supportsCheckpoint() && !needsCheckpoint()) {
- String revertMsg = "Reverting back to safe state. Marking "
- + session.sessionId() + " as failed.";
- final String reasonForRevert = getReasonForRevert();
- if (!TextUtils.isEmpty(reasonForRevert)) {
- revertMsg += " Reason for revert: " + reasonForRevert;
- }
- Slog.d(TAG, revertMsg);
- session.setSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, revertMsg);
- return;
+ // If checkpoint is supported, then we only resume sessions if we are in checkpointing mode.
+ // If not, we fail all sessions.
+ if (supportsCheckpoint && !needsCheckpoint) {
+ String revertMsg = "Reverting back to safe state. Marking " + session.sessionId()
+ + " as failed.";
+ final String reasonForRevert = getReasonForRevert();
+ if (!TextUtils.isEmpty(reasonForRevert)) {
+ revertMsg += " Reason for revert: " + reasonForRevert;
}
- } catch (RemoteException e) {
- // Cannot continue staged install without knowing if fs-checkpoint is supported
- Slog.e(TAG, "Checkpoint support unknown. Aborting staged install for session "
- + session.sessionId(), e);
- // TODO: Mark all staged sessions together and reboot only once
- session.setSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
- "Checkpoint support unknown. Aborting staged install.");
- if (hasApex) {
- mApexManager.revertActiveSessions();
- }
- mPowerManager.reboot("Checkpoint support unknown");
+ Slog.d(TAG, revertMsg);
+ session.setSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, revertMsg);
return;
}
- // Check if apex packages in the session failed to activate
- if (hasApex) {
- if (apexSessionInfo == null) {
- final String errorMsg = "apexd did not know anything about a staged session "
- + "supposed to be activated";
- throw new PackageManagerException(
- SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
- }
- if (isApexSessionFailed(apexSessionInfo)) {
- String errorMsg = "APEX activation failed. Check logcat messages from apexd "
- + "for more information.";
- if (!TextUtils.isEmpty(mNativeFailureReason)) {
- errorMsg = "Session reverted due to crashing native process: "
- + mNativeFailureReason;
- }
- throw new PackageManagerException(
- SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
- }
- if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
- // Apexd did not apply the session for some unknown reason. There is no
- // guarantee that apexd will install it next time. Safer to proactively mark
- // it as failed.
- final String errorMsg = "Staged session " + session.sessionId() + "at boot "
- + "didn't activate nor fail. Marking it as failed anyway.";
- throw new PackageManagerException(
- SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
- }
- }
-
// Handle apk and apk-in-apex installation
if (hasApex) {
checkInstallationOfApkInApexSuccessful(session);
@@ -622,28 +555,24 @@
Slog.d(TAG, "Marking session " + session.sessionId() + " as applied");
session.setSessionApplied();
if (hasApex) {
- try {
- if (supportsCheckpoint()) {
- // Store the session ID, which will be marked as successful by ApexManager
- // upon boot completion.
- synchronized (mSuccessfulStagedSessionIds) {
- mSuccessfulStagedSessionIds.add(session.sessionId());
- }
- } else {
- // Mark sessions as successful immediately on non-checkpointing devices.
- mApexManager.markStagedSessionSuccessful(session.sessionId());
+ if (supportsCheckpoint) {
+ // Store the session ID, which will be marked as successful by ApexManager upon
+ // boot completion.
+ synchronized (mSuccessfulStagedSessionIds) {
+ mSuccessfulStagedSessionIds.add(session.sessionId());
}
- } catch (RemoteException e) {
- Slog.w(TAG, "Checkpoint support unknown, marking session as successful "
- + "immediately.");
+ } else {
+ // Mark sessions as successful immediately on non-checkpointing devices.
mApexManager.markStagedSessionSuccessful(session.sessionId());
}
}
}
- void onInstallationFailure(StagedSession session, PackageManagerException e) {
+ void onInstallationFailure(StagedSession session, PackageManagerException e,
+ boolean supportsCheckpoint, boolean needsCheckpoint) {
session.setSessionFailed(e.error, e.getMessage());
- abortCheckpoint(session.sessionId(), e.getMessage());
+ abortCheckpoint("Failed to install sessionId: " + session.sessionId()
+ + " Error: " + e.getMessage(), supportsCheckpoint, needsCheckpoint);
// If checkpoint is not supported, we have to handle failure for one staged session.
if (!session.containsApexSession()) {
@@ -767,8 +696,13 @@
"Cannot stage session " + session.sessionId() + " with package name null");
}
- boolean supportsCheckpoint = ((StorageManager) mContext.getSystemService(
- Context.STORAGE_SERVICE)).isCheckpointSupported();
+ boolean supportsCheckpoint;
+ try {
+ supportsCheckpoint = PackageHelper.getStorageManager().supportsCheckpoint();
+ } catch (RemoteException e) {
+ throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+ "Can't query fs-checkpoint status : " + e);
+ }
final boolean isRollback = isRollback(session);
@@ -911,60 +845,166 @@
|| apexSessionInfo.isRevertFailed;
}
- void restoreSession(@NonNull StagedSession session, boolean isDeviceUpgrading) {
- if (session.hasParentSessionId()) {
- // Only parent sessions can be restored
- return;
+ private void handleNonReadyAndDestroyedSessions(List<StagedSession> sessions) {
+ int j = sessions.size();
+ for (int i = 0; i < j; ) {
+ // Maintain following invariant:
+ // * elements at positions [0, i) should be kept
+ // * elements at positions [j, n) should be remove.
+ // * n = sessions.size()
+ StagedSession session = sessions.get(i);
+ if (session.isDestroyed()) {
+ // Device rebooted before abandoned session was cleaned up.
+ session.abandon();
+ StagedSession session2 = sessions.set(j - 1, session);
+ sessions.set(i, session2);
+ j--;
+ } else if (!session.isSessionReady()) {
+ // The framework got restarted before the pre-reboot verification could complete,
+ // restart the verification.
+ mPreRebootVerificationHandler.startPreRebootVerification(session);
+ StagedSession session2 = sessions.set(j - 1, session);
+ sessions.set(i, session2);
+ j--;
+ } else {
+ i++;
+ }
}
- // Store this parent session which will be used to check overlapping later
- createSession(session);
- // The preconditions used during pre-reboot verification might have changed when device
- // is upgrading. Updated staged sessions to activation failed before we resume the session.
- StagedSession sessionToResume = session;
- if (isDeviceUpgrading && !sessionToResume.isInTerminalState()) {
- sessionToResume.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "Build fingerprint has changed");
- return;
- }
- checkStateAndResume(sessionToResume);
+ // Delete last j elements.
+ sessions.subList(j, sessions.size()).clear();
}
- private void checkStateAndResume(@NonNull StagedSession session) {
- // Do not resume session if boot completed already
+ void restoreSessions(@NonNull List<StagedSession> sessions, boolean isDeviceUpgrading) {
+ // Do not resume sessions if boot completed already
if (SystemProperties.getBoolean("sys.boot_completed", false)) {
return;
}
- if (!session.isCommitted()) {
- // Session hasn't been committed yet, ignore.
+ for (int i = 0; i < sessions.size(); i++) {
+ StagedSession session = sessions.get(i);
+ // Quick check that PackageInstallerService gave us sessions we expected.
+ Preconditions.checkArgument(!session.hasParentSessionId(),
+ session.sessionId() + " is a child session");
+ Preconditions.checkArgument(session.isCommitted(),
+ session.sessionId() + " is not committed");
+ Preconditions.checkArgument(!session.isInTerminalState(),
+ session.sessionId() + " is in terminal state");
+ // Store this parent session which will be used to check overlapping later
+ createSession(session);
+ }
+
+ if (isDeviceUpgrading) {
+ // TODO(ioffe): check that corresponding apex sessions are failed.
+ // The preconditions used during pre-reboot verification might have changed when device
+ // is upgrading. Fail all the sessions and exit early.
+ for (int i = 0; i < sessions.size(); i++) {
+ StagedSession session = sessions.get(i);
+ session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+ "Build fingerprint has changed");
+ }
return;
}
- // Check the state of the session and decide what to do next.
- if (session.isSessionFailed() || session.isSessionApplied()) {
- // Final states, nothing to do.
+
+ boolean needsCheckpoint = false;
+ boolean supportsCheckpoint = false;
+ try {
+ supportsCheckpoint = PackageHelper.getStorageManager().supportsCheckpoint();
+ needsCheckpoint = PackageHelper.getStorageManager().needsCheckpoint();
+ } catch (RemoteException e) {
+ // This means that vold has crashed, and device is in a bad state.
+ throw new IllegalStateException("Failed to get checkpoint status", e);
+ }
+
+ if (sessions.size() > 1 && !supportsCheckpoint) {
+ throw new IllegalStateException("Detected multiple staged sessions on a device without "
+ + "fs-checkpoint support");
+ }
+
+ // Do a set of quick checks before resuming individual sessions:
+ // 1. Schedule a pre-reboot verification for non-ready sessions.
+ // 2. Abandon destroyed sessions.
+ handleNonReadyAndDestroyedSessions(sessions); // mutates |sessions|
+
+ // 3. Check state of apex sessions is consistent. All non-applied sessions will be marked
+ // as failed.
+ final SparseArray<ApexSessionInfo> apexSessions = mApexManager.getSessions();
+ boolean hasFailedApexSession = false;
+ boolean hasAppliedApexSession = false;
+ for (int i = 0; i < sessions.size(); i++) {
+ StagedSession session = sessions.get(i);
+ if (!session.containsApexSession()) {
+ // At this point we are only interested in apex sessions.
+ continue;
+ }
+ final ApexSessionInfo apexSession = apexSessions.get(session.sessionId());
+ if (apexSession == null || apexSession.isUnknown) {
+ hasFailedApexSession = true;
+ session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, "apexd did "
+ + "not know anything about a staged session supposed to be activated");
+ continue;
+ } else if (isApexSessionFailed(apexSession)) {
+ hasFailedApexSession = true;
+ String errorMsg = "APEX activation failed. Check logcat messages from apexd "
+ + "for more information.";
+ if (!TextUtils.isEmpty(apexSession.crashingNativeProcess)) {
+ prepareForLoggingApexdRevert(session, apexSession.crashingNativeProcess);
+ errorMsg = "Session reverted due to crashing native process: "
+ + apexSession.crashingNativeProcess;
+ }
+ session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
+ continue;
+ } else if (apexSession.isActivated || apexSession.isSuccess) {
+ hasAppliedApexSession = true;
+ continue;
+ } else if (apexSession.isStaged) {
+ // Apexd did not apply the session for some unknown reason. There is no guarantee
+ // that apexd will install it next time. Safer to proactively mark it as failed.
+ hasFailedApexSession = true;
+ session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+ "Staged session " + session.sessionId() + " at boot didn't activate nor "
+ + "fail. Marking it as failed anyway.");
+ } else {
+ Slog.w(TAG, "Apex session " + session.sessionId() + " is in impossible state");
+ hasFailedApexSession = true;
+ session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+ "Impossible state");
+ }
+ }
+
+ if (hasAppliedApexSession && hasFailedApexSession) {
+ abortCheckpoint("Found both applied and failed apex sessions", supportsCheckpoint,
+ needsCheckpoint);
return;
}
- if (session.isDestroyed()) {
- // Device rebooted before abandoned session was cleaned up.
- session.abandon();
+
+ if (hasFailedApexSession) {
+ // Either of those means that we failed at least one apex session, hence we should fail
+ // all other sessions.
+ for (int i = 0; i < sessions.size(); i++) {
+ StagedSession session = sessions.get(i);
+ if (session.isSessionFailed()) {
+ // Session has been already failed in the loop above.
+ continue;
+ }
+ session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+ "Another apex session failed");
+ }
return;
}
- if (!session.isSessionReady()) {
- // The framework got restarted before the pre-reboot verification could complete,
- // restart the verification.
- mPreRebootVerificationHandler.startPreRebootVerification(session);
- } else {
- // Session had already being marked ready. Start the checks to verify if there is any
- // follow-up work.
+
+ // Time to resume sessions.
+ for (int i = 0; i < sessions.size(); i++) {
+ StagedSession session = sessions.get(i);
try {
- resumeSession(session);
+ resumeSession(session, supportsCheckpoint, needsCheckpoint);
} catch (PackageManagerException e) {
- onInstallationFailure(session, e);
+ onInstallationFailure(session, e, supportsCheckpoint, needsCheckpoint);
} catch (Exception e) {
Slog.e(TAG, "Staged install failed due to unhandled exception", e);
onInstallationFailure(session, new PackageManagerException(
SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "Staged install failed due to unhandled exception: " + e));
+ "Staged install failed due to unhandled exception: " + e),
+ supportsCheckpoint, needsCheckpoint);
}
}
}
@@ -992,9 +1032,7 @@
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
- mPreRebootVerificationHandler.readyToStart();
- BackgroundThread.getExecutor().execute(
- () -> logFailedApexSessionsIfNecessary());
+ onBootCompletedBroadcastReceived();
ctx.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
@@ -1002,6 +1040,12 @@
mFailureReasonFile.delete();
}
+ @VisibleForTesting
+ void onBootCompletedBroadcastReceived() {
+ mPreRebootVerificationHandler.readyToStart();
+ BackgroundThread.getExecutor().execute(() -> logFailedApexSessionsIfNecessary());
+ }
+
private static class LocalIntentReceiverSync {
private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
@@ -1286,9 +1330,8 @@
private void handlePreRebootVerification_End(@NonNull StagedSession session) {
// Before marking the session as ready, start checkpoint service if available
try {
- IStorageManager storageManager = PackageHelper.getStorageManager();
- if (storageManager.supportsCheckpoint()) {
- storageManager.startCheckpoint(2);
+ if (PackageHelper.getStorageManager().supportsCheckpoint()) {
+ PackageHelper.getStorageManager().startCheckpoint(2);
}
} catch (Exception e) {
// Failed to get hold of StorageManager
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 0e88862..e05ef48 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,4 +1,3 @@
-moltmann@google.com
zhanghai@google.com
per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
@@ -7,5 +6,4 @@
per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
per-file DefaultPermissionGrantPolicy.java = patb@google.com
per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
-per-file DefaultPermissionGrantPolicy.java = moltmann@google.com
per-file DefaultPermissionGrantPolicy.java = zhanghai@google.com
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 0669581..e486f08 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2590,6 +2590,7 @@
boolean runtimePermissionsRevoked = false;
int[] updatedUserIds = EMPTY_INT_ARRAY;
+ ArraySet<String> isPrivilegedPermissionAllowlisted = null;
ArraySet<String> shouldGrantSignaturePermission = null;
ArraySet<String> shouldGrantInternalPermission = null;
final List<String> requestedPermissions = pkg.getRequestedPermissions();
@@ -2604,7 +2605,14 @@
if (permission == null) {
continue;
}
- if (permission.isSignature() && (shouldGrantSignaturePermission(pkg, permission)
+ if (permission.isPrivileged()
+ && checkPrivilegedPermissionAllowlist(pkg, ps, permission)) {
+ if (isPrivilegedPermissionAllowlisted == null) {
+ isPrivilegedPermissionAllowlisted = new ArraySet<>();
+ }
+ isPrivilegedPermissionAllowlisted.add(permissionName);
+ }
+ if (permission.isSignature() && (shouldGrantPermissionBySignature(pkg, permission)
|| shouldGrantPermissionByProtectionFlags(pkg, ps, permission))) {
if (shouldGrantSignaturePermission == null) {
shouldGrantSignaturePermission = new ArraySet<>();
@@ -2830,13 +2838,17 @@
if ((bp.isNormal() && shouldGrantNormalPermission)
|| (bp.isSignature()
- && ((shouldGrantSignaturePermission != null
- && shouldGrantSignaturePermission.contains(permName))
+ && (!bp.isPrivileged() || CollectionUtils.contains(
+ isPrivilegedPermissionAllowlisted, permName))
+ && (CollectionUtils.contains(shouldGrantSignaturePermission,
+ permName)
|| ((bp.isDevelopment() || bp.isRole())
&& origState.isPermissionGranted(permName))))
|| (bp.isInternal()
- && ((shouldGrantInternalPermission != null
- && shouldGrantInternalPermission.contains(permName))
+ && (!bp.isPrivileged() || CollectionUtils.contains(
+ isPrivilegedPermissionAllowlisted, permName))
+ && (CollectionUtils.contains(shouldGrantInternalPermission,
+ permName)
|| ((bp.isDevelopment() || bp.isRole())
&& origState.isPermissionGranted(permName))))) {
// Grant an install permission.
@@ -3343,7 +3355,92 @@
return allowed;
}
- private boolean shouldGrantSignaturePermission(@NonNull AndroidPackage pkg,
+ private boolean checkPrivilegedPermissionAllowlist(@NonNull AndroidPackage pkg,
+ @NonNull PackageSetting packageSetting, @NonNull Permission permission) {
+ if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {
+ return true;
+ }
+ final String packageName = pkg.getPackageName();
+ if (Objects.equals(packageName, PLATFORM_PACKAGE_NAME)) {
+ return true;
+ }
+ if (!pkg.isPrivileged()) {
+ return true;
+ }
+ if (!Objects.equals(permission.getPackageName(), PLATFORM_PACKAGE_NAME)) {
+ return true;
+ }
+ final String permissionName = permission.getName();
+ if (isInSystemConfigPrivAppPermissions(pkg, permissionName)) {
+ return true;
+ }
+ // Only enforce the allowlist on boot
+ if (!mSystemReady
+ // Updated system apps do not need to be allowlisted
+ && !packageSetting.getPkgState().isUpdatedSystemApp()) {
+ final ApexManager apexManager = ApexManager.getInstance();
+ final String containingApexPackageName =
+ apexManager.getActiveApexPackageNameContainingPackage(packageName);
+ final boolean isInUpdatedApex = containingApexPackageName != null
+ && !apexManager.isFactory(apexManager.getPackageInfo(containingApexPackageName,
+ MATCH_ACTIVE_PACKAGE));
+ // Apps that are in updated apexs' do not need to be allowlisted
+ if (!isInUpdatedApex) {
+ // it's only a reportable violation if the permission isn't explicitly
+ // denied
+ if (isInSystemConfigPrivAppDenyPermissions(pkg, permissionName)) {
+ return false;
+ }
+ Slog.w(TAG, "Privileged permission " + permissionName + " for package "
+ + packageName + " (" + pkg.getPath()
+ + ") not in privapp-permissions allowlist");
+ if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
+ synchronized (mLock) {
+ if (mPrivappPermissionsViolations == null) {
+ mPrivappPermissionsViolations = new ArraySet<>();
+ }
+ mPrivappPermissionsViolations.add(packageName + " (" + pkg.getPath() + "): "
+ + permissionName);
+ }
+ }
+ }
+ }
+ return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE;
+ }
+
+ private boolean isInSystemConfigPrivAppPermissions(@NonNull AndroidPackage pkg,
+ @NonNull String permission) {
+ final SystemConfig systemConfig = SystemConfig.getInstance();
+ final Set<String> permissions;
+ if (pkg.isVendor()) {
+ permissions = systemConfig.getVendorPrivAppPermissions(pkg.getPackageName());
+ } else if (pkg.isProduct()) {
+ permissions = systemConfig.getProductPrivAppPermissions(pkg.getPackageName());
+ } else if (pkg.isSystemExt()) {
+ permissions = systemConfig.getSystemExtPrivAppPermissions(pkg.getPackageName());
+ } else {
+ permissions = systemConfig.getPrivAppPermissions(pkg.getPackageName());
+ }
+ return CollectionUtils.contains(permissions, permission);
+ }
+
+ private boolean isInSystemConfigPrivAppDenyPermissions(@NonNull AndroidPackage pkg,
+ @NonNull String permission) {
+ final SystemConfig systemConfig = SystemConfig.getInstance();
+ final Set<String> permissions;
+ if (pkg.isVendor()) {
+ permissions = systemConfig.getVendorPrivAppDenyPermissions(pkg.getPackageName());
+ } else if (pkg.isProduct()) {
+ permissions = systemConfig.getProductPrivAppDenyPermissions(pkg.getPackageName());
+ } else if (pkg.isSystemExt()) {
+ permissions = systemConfig.getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
+ } else {
+ permissions = systemConfig.getPrivAppDenyPermissions(pkg.getPackageName());
+ }
+ return CollectionUtils.contains(permissions, permission);
+ }
+
+ private boolean shouldGrantPermissionBySignature(@NonNull AndroidPackage pkg,
@NonNull Permission bp) {
// expect single system package
String systemPackageName = ArrayUtils.firstOrNull(mPackageManagerInt.getKnownPackageNames(
@@ -3373,8 +3470,7 @@
private boolean shouldGrantPermissionByProtectionFlags(@NonNull AndroidPackage pkg,
@NonNull PackageSetting pkgSetting, @NonNull Permission bp) {
boolean allowed = false;
- final boolean isVendorPrivilegedPermission = bp.isVendorPrivileged();
- final boolean isPrivilegedPermission = bp.isPrivileged() || isVendorPrivilegedPermission;
+ final boolean isPrivilegedPermission = bp.isPrivileged();
final boolean isOemPermission = bp.isOem();
if (!allowed && (isPrivilegedPermission || isOemPermission) && pkg.isSystem()) {
final String permissionName = bp.getName();
@@ -3386,19 +3482,18 @@
final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
if (disabledPkg != null && disabledPkg.getRequestedPermissions().contains(
permissionName)) {
- allowed = (isPrivilegedPermission && canGrantPrivilegedPermission(disabledPkg,
- true, bp)) || (isOemPermission && canGrantOemPermission(disabledPkg,
+ allowed = (isPrivilegedPermission && disabledPkg.isPrivileged())
+ || (isOemPermission && canGrantOemPermission(disabledPkg,
permissionName));
}
} else {
- allowed = (isPrivilegedPermission && canGrantPrivilegedPermission(pkg, false, bp))
+ allowed = (isPrivilegedPermission && pkg.isPrivileged())
|| (isOemPermission && canGrantOemPermission(pkg, permissionName));
}
// In any case, don't grant a privileged permission to privileged vendor apps, if
// the permission's protectionLevel does not have the extra 'vendorPrivileged'
// flag.
- if (allowed && isPrivilegedPermission && !isVendorPrivilegedPermission
- && pkg.isVendor()) {
+ if (allowed && isPrivilegedPermission && !bp.isVendorPrivileged() && pkg.isVendor()) {
Slog.w(TAG, "Permission " + permissionName
+ " cannot be granted to privileged vendor apk " + pkg.getPackageName()
+ " because it isn't a 'vendorPrivileged' permission.");
@@ -3541,90 +3636,6 @@
return mPackageManagerInt.getPackageSetting(sourcePackageName);
}
- private boolean canGrantPrivilegedPermission(@NonNull AndroidPackage pkg,
- boolean isUpdatedSystemApp, @NonNull Permission permission) {
- if (!pkg.isPrivileged()) {
- return false;
- }
- final boolean isPlatformPermission = PLATFORM_PACKAGE_NAME.equals(
- permission.getPackageName());
- if (!isPlatformPermission) {
- return true;
- }
- if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {
- return true;
- }
- final String permissionName = permission.getName();
- if (isInSystemConfigPrivAppPermissions(pkg, permissionName)) {
- return true;
- }
- // Only enforce the allowlist on boot
- if (!mSystemReady
- // Updated system apps do not need to be allowlisted
- && !isUpdatedSystemApp) {
- final ApexManager apexManager = ApexManager.getInstance();
- final String packageName = pkg.getPackageName();
- final String containingApexPackageName =
- apexManager.getActiveApexPackageNameContainingPackage(packageName);
- final boolean isInUpdatedApex = containingApexPackageName != null
- && !apexManager.isFactory(apexManager.getPackageInfo(containingApexPackageName,
- MATCH_ACTIVE_PACKAGE));
- // Apps that are in updated apexs' do not need to be allowlisted
- if (!isInUpdatedApex) {
- // it's only a reportable violation if the permission isn't explicitly
- // denied
- if (isInSystemConfigPrivAppDenyPermissions(pkg, permissionName)) {
- return false;
- }
- Slog.w(TAG, "Privileged permission " + permissionName + " for package "
- + packageName + " (" + pkg.getPath()
- + ") not in privapp-permissions allowlist");
- if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
- synchronized (mLock) {
- if (mPrivappPermissionsViolations == null) {
- mPrivappPermissionsViolations = new ArraySet<>();
- }
- mPrivappPermissionsViolations.add(packageName + " (" + pkg.getPath() + "): "
- + permissionName);
- }
- }
- }
- }
- return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE;
- }
-
- private boolean isInSystemConfigPrivAppPermissions(@NonNull AndroidPackage pkg,
- @NonNull String permission) {
- final SystemConfig systemConfig = SystemConfig.getInstance();
- final Set<String> permissions;
- if (pkg.isVendor()) {
- permissions = systemConfig.getVendorPrivAppPermissions(pkg.getPackageName());
- } else if (pkg.isProduct()) {
- permissions = systemConfig.getProductPrivAppPermissions(pkg.getPackageName());
- } else if (pkg.isSystemExt()) {
- permissions = systemConfig.getSystemExtPrivAppPermissions(pkg.getPackageName());
- } else {
- permissions = systemConfig.getPrivAppPermissions(pkg.getPackageName());
- }
- return permissions != null && permissions.contains(permission);
- }
-
- private boolean isInSystemConfigPrivAppDenyPermissions(@NonNull AndroidPackage pkg,
- @NonNull String permission) {
- final SystemConfig systemConfig = SystemConfig.getInstance();
- final Set<String> permissions;
- if (pkg.isVendor()) {
- permissions = systemConfig.getVendorPrivAppDenyPermissions(pkg.getPackageName());
- } else if (pkg.isProduct()) {
- permissions = systemConfig.getProductPrivAppDenyPermissions(pkg.getPackageName());
- } else if (pkg.isSystemExt()) {
- permissions = systemConfig.getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
- } else {
- permissions = systemConfig.getPrivAppDenyPermissions(pkg.getPackageName());
- }
- return permissions != null && permissions.contains(permission);
- }
-
private static boolean canGrantOemPermission(AndroidPackage pkg, String permission) {
if (!pkg.isOem()) {
return false;
diff --git a/services/core/java/com/android/server/role/OWNERS b/services/core/java/com/android/server/role/OWNERS
index b94d988..31e3549 100644
--- a/services/core/java/com/android/server/role/OWNERS
+++ b/services/core/java/com/android/server/role/OWNERS
@@ -1,5 +1,4 @@
svetoslavganov@google.com
-moltmann@google.com
zhanghai@google.com
evanseverson@google.com
eugenesusla@google.com
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index bd93e04..ceebe95 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -847,8 +847,6 @@
mWmService.openSurfaceTransaction();
try {
applySurfaceChangesTransaction();
- // Send any pending task-info changes that were queued-up during a layout deferment
- mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
mWmService.mSyncEngine.onSurfacePlacement();
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
@@ -861,6 +859,8 @@
}
}
+ // Send any pending task-info changes that were queued-up during a layout deferment
+ mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
checkAppTransitionReady(surfacePlacer);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 1c4b034..a7abf6a 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -149,7 +149,7 @@
"android.hardware.power@1.1",
"android.hardware.power-V1-cpp",
"android.hardware.power.stats@1.0",
- "android.hardware.power.stats-ndk_platform",
+ "android.hardware.power.stats-V1-ndk_platform",
"android.hardware.thermal@1.0",
"android.hardware.tv.input@1.0",
"android.hardware.vibrator-V2-cpp",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 07eb7bf..b063e67 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -62,6 +62,7 @@
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
import static android.app.admin.DevicePolicyManager.NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+import static android.app.admin.DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
@@ -92,7 +93,6 @@
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED;
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED;
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_STARTING_PROFILE_FAILED;
-import static android.app.admin.DevicePolicyManager.UNSAFE_OPERATION_REASON_NONE;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -157,9 +157,9 @@
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
+import android.app.admin.DevicePolicyManager.OperationSafetyReason;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
-import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicySafetyChecker;
import android.app.admin.DeviceStateCache;
@@ -1101,7 +1101,7 @@
*/
private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
int reason = getUnsafeOperationReason(operation);
- if (reason == UNSAFE_OPERATION_REASON_NONE) return;
+ if (reason == OPERATION_SAFETY_REASON_NONE) return;
if (mSafetyChecker == null) {
// Happens on CTS after it's set just once (by OneTimeSafetyChecker)
@@ -1114,23 +1114,28 @@
/**
* Returns whether it's safe to execute the given {@code operation}, and why.
*/
- @UnsafeOperationReason
+ @OperationSafetyReason
int getUnsafeOperationReason(@DevicePolicyOperation int operation) {
- return mSafetyChecker == null ? UNSAFE_OPERATION_REASON_NONE
+ return mSafetyChecker == null ? OPERATION_SAFETY_REASON_NONE
: mSafetyChecker.getUnsafeOperationReason(operation);
}
@Override
public void setNextOperationSafety(@DevicePolicyOperation int operation,
- @UnsafeOperationReason int reason) {
+ @OperationSafetyReason int reason) {
Preconditions.checkCallAuthorization(
hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
Slog.i(LOG_TAG, String.format("setNextOperationSafety(%s, %s)",
DevicePolicyManager.operationToString(operation),
- DevicePolicyManager.unsafeOperationReasonToString(reason)));
+ DevicePolicyManager.operationSafetyReasonToString(reason)));
mSafetyChecker = new OneTimeSafetyChecker(this, operation, reason);
}
+ @Override
+ public boolean isSafeOperation(@OperationSafetyReason int reason) {
+ return mSafetyChecker == null ? true : mSafetyChecker.isSafeOperation(reason);
+ }
+
// Used by DevicePolicyManagerServiceShellCommand
List<OwnerDto> listAllOwners() {
Preconditions.checkCallAuthorization(
@@ -7522,19 +7527,23 @@
sendActiveAdminCommand(action, extras, deviceOwnerUserId, receiverComponent);
}
- private void sendProfileOwnerCommand(String action, Bundle extras, int userHandle) {
- sendActiveAdminCommand(action, extras, userHandle,
- mOwners.getProfileOwnerComponent(userHandle));
+ private void sendProfileOwnerCommand(String action, Bundle extras, @UserIdInt int userId) {
+ sendActiveAdminCommand(action, extras, userId,
+ mOwners.getProfileOwnerComponent(userId));
}
private void sendActiveAdminCommand(String action, Bundle extras,
- int userHandle, ComponentName receiverComponent) {
+ @UserIdInt int userId, ComponentName receiverComponent) {
+ if (VERBOSE_LOG) {
+ Slog.v(LOG_TAG, "sending intent " + action + " to "
+ + receiverComponent.flattenToShortString() + " on user " + userId);
+ }
final Intent intent = new Intent(action);
intent.setComponent(receiverComponent);
if (extras != null) {
intent.putExtras(extras);
}
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userHandle));
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
private void sendOwnerChangedBroadcast(String broadcast, int userId) {
@@ -12224,6 +12233,32 @@
packageName, findInteractAcrossProfilesResetMode(packageName), userId);
}
+ @Override
+ public void notifyUnsafeOperationStateChanged(DevicePolicySafetyChecker checker, int reason,
+ boolean isSafe) {
+ // TODO(b/178494483): use EventLog instead
+ // TODO(b/178494483): log metrics?
+ if (VERBOSE_LOG) {
+ Slog.v(LOG_TAG, String.format("notifyUnsafeOperationStateChanged(): %s=%b",
+ DevicePolicyManager.operationSafetyReasonToString(reason), isSafe));
+ }
+
+ Preconditions.checkArgument(mSafetyChecker == checker,
+ "invalid checker: should be %s, was %s", mSafetyChecker, checker);
+
+ Bundle extras = new Bundle();
+ extras.putInt(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_REASON, reason);
+ extras.putBoolean(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_STATE, isSafe);
+
+ // TODO(b/178494483): add CTS test
+ sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
+ extras);
+ for (int profileOwnerId : mOwners.getProfileOwnerKeys()) {
+ sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
+ extras, profileOwnerId);
+ }
+ }
+
private @Mode int findInteractAcrossProfilesResetMode(String packageName) {
return getDefaultCrossProfilePackages().contains(packageName)
? AppOpsManager.MODE_ALLOWED
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 222c987..5484a14 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -27,6 +27,7 @@
final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
private static final String CMD_IS_SAFE_OPERATION = "is-operation-safe";
+ private static final String CMD_IS_SAFE_OPERATION_BY_REASON = "is-operation-safe-by-reason";
private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
private static final String CMD_LIST_OWNERS = "list-owners";
@@ -53,6 +54,8 @@
switch (cmd) {
case CMD_IS_SAFE_OPERATION:
return runIsSafeOperation(pw);
+ case CMD_IS_SAFE_OPERATION_BY_REASON:
+ return runIsSafeOperationByReason(pw);
case CMD_SET_SAFE_OPERATION:
return runSetSafeOperation(pw);
case CMD_LIST_OWNERS:
@@ -73,12 +76,13 @@
return -1;
}
-
private void showHelp(PrintWriter pw) {
pw.printf(" help\n");
pw.printf(" Prints this help text.\n\n");
pw.printf(" %s <OPERATION_ID>\n", CMD_IS_SAFE_OPERATION);
pw.printf(" Checks if the give operation is safe \n\n");
+ pw.printf(" %s <REASON_ID>\n", CMD_IS_SAFE_OPERATION_BY_REASON);
+ pw.printf(" Checks if the operations are safe for the given reason\n\n");
pw.printf(" %s <OPERATION_ID> <REASON_ID>\n", CMD_SET_SAFE_OPERATION);
pw.printf(" Emulates the result of the next call to check if the given operation is safe"
+ " \n\n");
@@ -89,10 +93,19 @@
private int runIsSafeOperation(PrintWriter pw) {
int operation = Integer.parseInt(getNextArgRequired());
int reason = mService.getUnsafeOperationReason(operation);
- boolean safe = reason == DevicePolicyManager.UNSAFE_OPERATION_REASON_NONE;
+ boolean safe = reason == DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
pw.printf("Operation %s is %b. Reason: %s\n",
DevicePolicyManager.operationToString(operation), safe,
- DevicePolicyManager.unsafeOperationReasonToString(reason));
+ DevicePolicyManager.operationSafetyReasonToString(reason));
+ return 0;
+ }
+
+ private int runIsSafeOperationByReason(PrintWriter pw) {
+ int reason = Integer.parseInt(getNextArgRequired());
+ boolean safe = mService.isSafeOperation(reason);
+ pw.printf("Operations affected by %s are %s\n",
+ DevicePolicyManager.operationSafetyReasonToString(reason),
+ (safe ? "SAFE" : "UNSAFE"));
return 0;
}
@@ -102,7 +115,7 @@
mService.setNextOperationSafety(operation, reason);
pw.printf("Next call to check operation %s will return %s\n",
DevicePolicyManager.operationToString(operation),
- DevicePolicyManager.unsafeOperationReasonToString(reason));
+ DevicePolicyManager.operationSafetyReasonToString(reason));
return 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
index 883f95d..7de1bd5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
@@ -15,16 +15,18 @@
*/
package com.android.server.devicepolicy;
-import static android.app.admin.DevicePolicyManager.UNSAFE_OPERATION_REASON_NONE;
+import static android.app.admin.DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
+import static android.app.admin.DevicePolicyManager.operationSafetyReasonToString;
import static android.app.admin.DevicePolicyManager.operationToString;
-import static android.app.admin.DevicePolicyManager.unsafeOperationReasonToString;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
-import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
+import android.app.admin.DevicePolicyManager.OperationSafetyReason;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicySafetyChecker;
import android.util.Slog;
import com.android.internal.os.IResultReceiver;
+import com.android.server.LocalServices;
import java.util.Objects;
@@ -43,10 +45,10 @@
private final DevicePolicyManagerService mService;
private final DevicePolicySafetyChecker mRealSafetyChecker;
private final @DevicePolicyOperation int mOperation;
- private final @UnsafeOperationReason int mReason;
+ private final @OperationSafetyReason int mReason;
OneTimeSafetyChecker(DevicePolicyManagerService service,
- @DevicePolicyOperation int operation, @UnsafeOperationReason int reason) {
+ @DevicePolicyOperation int operation, @OperationSafetyReason int reason) {
mService = Objects.requireNonNull(service);
mOperation = operation;
mReason = reason;
@@ -55,24 +57,42 @@
}
@Override
- @UnsafeOperationReason
+ @OperationSafetyReason
public int getUnsafeOperationReason(@DevicePolicyOperation int operation) {
String name = operationToString(operation);
- int reason = UNSAFE_OPERATION_REASON_NONE;
+ Slog.i(TAG, "getUnsafeOperationReason(" + name + ")");
+ int reason = OPERATION_SAFETY_REASON_NONE;
if (operation == mOperation) {
reason = mReason;
} else {
Slog.wtf(TAG, "invalid call to isDevicePolicyOperationSafe(): asked for " + name
+ ", should be " + operationToString(mOperation));
}
- Slog.i(TAG, "getDevicePolicyOperationSafety(" + name + "): returning "
- + unsafeOperationReasonToString(reason)
+ String reasonName = operationSafetyReasonToString(reason);
+ DevicePolicyManagerInternal dpmi = LocalServices
+ .getService(DevicePolicyManagerInternal.class);
+
+ Slog.i(TAG, "notifying " + reasonName + " is active");
+ dpmi.notifyUnsafeOperationStateChanged(this, reason, true);
+
+ Slog.i(TAG, "notifying " + reasonName + " is inactive");
+ dpmi.notifyUnsafeOperationStateChanged(this, reason, false);
+
+ Slog.i(TAG, "returning " + reasonName
+ " and restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
mService.setDevicePolicySafetyCheckerUnchecked(mRealSafetyChecker);
return reason;
}
@Override
+ public boolean isSafeOperation(@OperationSafetyReason int reason) {
+ boolean safe = mReason != reason;
+ Slog.i(TAG, "isSafeOperation(" + operationSafetyReasonToString(reason) + "): " + safe);
+
+ return safe;
+ }
+
+ @Override
public void onFactoryReset(IResultReceiver callback) {
throw new UnsupportedOperationException();
}
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index 2219d47..cbebe69 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -38,6 +38,7 @@
import android.annotation.UserIdInt;
import android.app.Application;
+import android.app.backup.BackupManager.OperationType;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
@@ -873,7 +874,8 @@
SecurityException.class,
() ->
backupManagerService.requestBackup(
- mUserTwoId, packages, observer, monitor, 0));
+ mUserTwoId, packages, observer, monitor, 0,
+ OperationType.BACKUP));
}
/**
@@ -891,9 +893,11 @@
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
- backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0);
+ backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0,
+ OperationType.BACKUP);
- verify(mUserTwoService).requestBackup(packages, observer, monitor, /* flags */ 0);
+ verify(mUserTwoService).requestBackup(packages, observer, monitor, /* flags */ 0,
+ OperationType.BACKUP);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
@@ -906,9 +910,11 @@
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
- backupManagerService.requestBackup(mUserOneId, packages, observer, monitor, /* flags */ 0);
+ backupManagerService.requestBackup(mUserOneId, packages, observer, monitor, /* flags */ 0,
+ OperationType.BACKUP);
- verify(mUserOneService).requestBackup(packages, observer, monitor, /* flags */ 0);
+ verify(mUserOneService).requestBackup(packages, observer, monitor, /* flags */ 0,
+ OperationType.BACKUP);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
@@ -921,9 +927,11 @@
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
- backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0);
+ backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0,
+ OperationType.BACKUP);
- verify(mUserOneService, never()).requestBackup(packages, observer, monitor, /* flags */ 0);
+ verify(mUserOneService, never()).requestBackup(packages, observer, monitor, /* flags */ 0,
+ OperationType.BACKUP);
}
/**
@@ -1084,9 +1092,11 @@
registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
- backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT);
+ backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
- verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
+ verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
}
/** Test that the backup service does not route methods for non-registered users. */
@@ -1096,9 +1106,11 @@
registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
- backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT);
+ backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
- verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
+ verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
new file mode 100644
index 0000000..195cc01
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.apex.ApexSessionInfo;
+import android.content.Context;
+import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
+import android.os.SystemProperties;
+import android.os.storage.IStorageManager;
+import android.platform.test.annotations.Presubmit;
+import android.util.SparseArray;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+@Presubmit
+@RunWith(JUnit4.class)
+public class StagingManagerTest {
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ @Mock private Context mContext;
+ @Mock private IStorageManager mStorageManager;
+ @Mock private ApexManager mApexManager;
+
+ private File mTmpDir;
+ private StagingManager mStagingManager;
+
+ private MockitoSession mMockitoSession;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(eq(Context.POWER_SERVICE))).thenReturn(null);
+
+ mMockitoSession = ExtendedMockito.mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .mockStatic(SystemProperties.class)
+ .mockStatic(PackageHelper.class)
+ .startMocking();
+
+ when(mStorageManager.supportsCheckpoint()).thenReturn(true);
+ when(mStorageManager.needsCheckpoint()).thenReturn(true);
+ when(PackageHelper.getStorageManager()).thenReturn(mStorageManager);
+
+ when(SystemProperties.get(eq("ro.apex.updatable"))).thenReturn("true");
+ when(SystemProperties.get(eq("ro.apex.updatable"), anyString())).thenReturn("true");
+
+ mTmpDir = mTemporaryFolder.newFolder("StagingManagerTest");
+ mStagingManager = new StagingManager(mContext, null, mApexManager);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
+ }
+
+ /**
+ * Tests that sessions committed later shouldn't cause earlier ones to fail the overlapping
+ * check.
+ */
+ @Test
+ public void checkNonOverlappingWithStagedSessions_laterSessionShouldNotFailEarlierOnes()
+ throws Exception {
+ // Create 2 sessions with overlapping packages
+ StagingManager.StagedSession session1 = createSession(111, "com.foo", 1);
+ StagingManager.StagedSession session2 = createSession(222, "com.foo", 2);
+
+ mStagingManager.createSession(session1);
+ mStagingManager.createSession(session2);
+ // Session1 should not fail in spite of the overlapping packages
+ mStagingManager.checkNonOverlappingWithStagedSessions(session1);
+ // Session2 should fail due to overlapping packages
+ assertThrows(PackageManagerException.class,
+ () -> mStagingManager.checkNonOverlappingWithStagedSessions(session2));
+ }
+
+ @Test
+ public void restoreSessions_nonParentSession_throwsIAE() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(239);
+ session.setParentSessionId(1543);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mStagingManager.restoreSessions(Arrays.asList(session), false));
+ }
+
+ @Test
+ public void restoreSessions_nonCommittedSession_throwsIAE() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(239);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mStagingManager.restoreSessions(Arrays.asList(session), false));
+ }
+
+ @Test
+ public void restoreSessions_terminalSession_throwsIAE() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(239);
+ session.setCommitted(true);
+ session.setSessionApplied();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mStagingManager.restoreSessions(Arrays.asList(session), false));
+ }
+
+ @Test
+ public void restoreSessions_deviceUpgrading_failsAllSessions() throws Exception {
+ FakeStagedSession session1 = new FakeStagedSession(37);
+ session1.setCommitted(true);
+ FakeStagedSession session2 = new FakeStagedSession(57);
+ session2.setCommitted(true);
+
+ mStagingManager.restoreSessions(Arrays.asList(session1, session2), true);
+
+ assertThat(session1.getErrorCode()).isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(session1.getErrorMessage()).isEqualTo("Build fingerprint has changed");
+
+ assertThat(session2.getErrorCode()).isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(session2.getErrorMessage()).isEqualTo("Build fingerprint has changed");
+ }
+
+ @Test
+ public void restoreSessions_multipleSessions_deviceWithoutFsCheckpointSupport_throwISE()
+ throws Exception {
+ FakeStagedSession session1 = new FakeStagedSession(37);
+ session1.setCommitted(true);
+ FakeStagedSession session2 = new FakeStagedSession(57);
+ session2.setCommitted(true);
+
+ when(mStorageManager.supportsCheckpoint()).thenReturn(false);
+
+ assertThrows(IllegalStateException.class,
+ () -> mStagingManager.restoreSessions(Arrays.asList(session1, session2), false));
+ }
+
+ @Test
+ public void restoreSessions_handlesDestroyedAndNotReadySessions() throws Exception {
+ FakeStagedSession destroyedApkSession = new FakeStagedSession(23);
+ destroyedApkSession.setCommitted(true);
+ destroyedApkSession.setDestroyed(true);
+
+ FakeStagedSession destroyedApexSession = new FakeStagedSession(37);
+ destroyedApexSession.setCommitted(true);
+ destroyedApexSession.setDestroyed(true);
+ destroyedApexSession.setIsApex(true);
+
+ FakeStagedSession nonReadyApkSession = new FakeStagedSession(57);
+ nonReadyApkSession.setCommitted(true);
+
+ FakeStagedSession nonReadyApexSession = new FakeStagedSession(73);
+ nonReadyApexSession.setCommitted(true);
+ nonReadyApexSession.setIsApex(true);
+
+ FakeStagedSession destroyedNonReadySession = new FakeStagedSession(101);
+ destroyedNonReadySession.setCommitted(true);
+ destroyedNonReadySession.setDestroyed(true);
+
+ FakeStagedSession regularApkSession = new FakeStagedSession(239);
+ regularApkSession.setCommitted(true);
+ regularApkSession.setSessionReady();
+
+ List<StagingManager.StagedSession> sessions = new ArrayList<>();
+ sessions.add(destroyedApkSession);
+ sessions.add(destroyedApexSession);
+ sessions.add(nonReadyApkSession);
+ sessions.add(nonReadyApexSession);
+ sessions.add(destroyedNonReadySession);
+ sessions.add(regularApkSession);
+
+ mStagingManager.restoreSessions(sessions, false);
+
+ assertThat(sessions).containsExactly(regularApkSession);
+ assertThat(destroyedApkSession.isDestroyed()).isTrue();
+ assertThat(destroyedApexSession.isDestroyed()).isTrue();
+ assertThat(destroyedNonReadySession.isDestroyed()).isTrue();
+
+ mStagingManager.onBootCompletedBroadcastReceived();
+ assertThat(nonReadyApkSession.hasPreRebootVerificationStarted()).isTrue();
+ assertThat(nonReadyApexSession.hasPreRebootVerificationStarted()).isTrue();
+ }
+
+ @Test
+ public void restoreSessions_unknownApexSession_failsAllSessions() throws Exception {
+ FakeStagedSession apkSession = new FakeStagedSession(239);
+ apkSession.setCommitted(true);
+ apkSession.setSessionReady();
+
+ FakeStagedSession apexSession = new FakeStagedSession(1543);
+ apexSession.setCommitted(true);
+ apexSession.setIsApex(true);
+ apexSession.setSessionReady();
+
+ List<StagingManager.StagedSession> sessions = new ArrayList<>();
+ sessions.add(apkSession);
+ sessions.add(apexSession);
+
+ when(mApexManager.getSessions()).thenReturn(new SparseArray<>());
+ mStagingManager.restoreSessions(sessions, false);
+
+ // Validate checkpoint wasn't aborted.
+ verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
+
+ assertThat(apexSession.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apexSession.getErrorMessage()).isEqualTo("apexd did not know anything about a "
+ + "staged session supposed to be activated");
+
+ assertThat(apkSession.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
+ }
+
+ @Test
+ public void restoreSessions_failedApexSessions_failsAllSessions() throws Exception {
+ FakeStagedSession apkSession = new FakeStagedSession(239);
+ apkSession.setCommitted(true);
+ apkSession.setSessionReady();
+
+ FakeStagedSession apexSession1 = new FakeStagedSession(1543);
+ apexSession1.setCommitted(true);
+ apexSession1.setIsApex(true);
+ apexSession1.setSessionReady();
+
+ FakeStagedSession apexSession2 = new FakeStagedSession(101);
+ apexSession2.setCommitted(true);
+ apexSession2.setIsApex(true);
+ apexSession2.setSessionReady();
+
+ FakeStagedSession apexSession3 = new FakeStagedSession(57);
+ apexSession3.setCommitted(true);
+ apexSession3.setIsApex(true);
+ apexSession3.setSessionReady();
+
+ ApexSessionInfo activationFailed = new ApexSessionInfo();
+ activationFailed.sessionId = 1543;
+ activationFailed.isActivationFailed = true;
+
+ ApexSessionInfo staged = new ApexSessionInfo();
+ staged.sessionId = 101;
+ staged.isStaged = true;
+
+ SparseArray<ApexSessionInfo> apexdSessions = new SparseArray<>();
+ apexdSessions.put(1543, activationFailed);
+ apexdSessions.put(101, staged);
+ when(mApexManager.getSessions()).thenReturn(apexdSessions);
+
+ List<StagingManager.StagedSession> sessions = new ArrayList<>();
+ sessions.add(apkSession);
+ sessions.add(apexSession1);
+ sessions.add(apexSession2);
+ sessions.add(apexSession3);
+
+ mStagingManager.restoreSessions(sessions, false);
+
+ // Validate checkpoint wasn't aborted.
+ verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
+
+ assertThat(apexSession1.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. Check logcat "
+ + "messages from apexd for more information.");
+
+ assertThat(apexSession2.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apexSession2.getErrorMessage()).isEqualTo("Staged session 101 at boot didn't "
+ + "activate nor fail. Marking it as failed anyway.");
+
+ assertThat(apexSession3.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apexSession3.getErrorMessage()).isEqualTo("apexd did not know anything about a "
+ + "staged session supposed to be activated");
+
+ assertThat(apkSession.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
+ }
+
+ @Test
+ public void restoreSessions_stagedApexSession_failsAllSessions() throws Exception {
+ FakeStagedSession apkSession = new FakeStagedSession(239);
+ apkSession.setCommitted(true);
+ apkSession.setSessionReady();
+
+ FakeStagedSession apexSession = new FakeStagedSession(1543);
+ apexSession.setCommitted(true);
+ apexSession.setIsApex(true);
+ apexSession.setSessionReady();
+
+ ApexSessionInfo staged = new ApexSessionInfo();
+ staged.sessionId = 1543;
+ staged.isStaged = true;
+
+ SparseArray<ApexSessionInfo> apexdSessions = new SparseArray<>();
+ apexdSessions.put(1543, staged);
+ when(mApexManager.getSessions()).thenReturn(apexdSessions);
+
+ List<StagingManager.StagedSession> sessions = new ArrayList<>();
+ sessions.add(apkSession);
+ sessions.add(apexSession);
+
+ mStagingManager.restoreSessions(sessions, false);
+
+ // Validate checkpoint wasn't aborted.
+ verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
+
+ assertThat(apexSession.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apexSession.getErrorMessage()).isEqualTo("Staged session 1543 at boot didn't "
+ + "activate nor fail. Marking it as failed anyway.");
+
+ assertThat(apkSession.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
+ }
+
+ @Test
+ public void restoreSessions_failedAndActivatedApexSessions_abortsCheckpoint() throws Exception {
+ FakeStagedSession apkSession = new FakeStagedSession(239);
+ apkSession.setCommitted(true);
+ apkSession.setSessionReady();
+
+ FakeStagedSession apexSession1 = new FakeStagedSession(1543);
+ apexSession1.setCommitted(true);
+ apexSession1.setIsApex(true);
+ apexSession1.setSessionReady();
+
+ FakeStagedSession apexSession2 = new FakeStagedSession(101);
+ apexSession2.setCommitted(true);
+ apexSession2.setIsApex(true);
+ apexSession2.setSessionReady();
+
+ FakeStagedSession apexSession3 = new FakeStagedSession(57);
+ apexSession3.setCommitted(true);
+ apexSession3.setIsApex(true);
+ apexSession3.setSessionReady();
+
+ FakeStagedSession apexSession4 = new FakeStagedSession(37);
+ apexSession4.setCommitted(true);
+ apexSession4.setIsApex(true);
+ apexSession4.setSessionReady();
+
+ ApexSessionInfo activationFailed = new ApexSessionInfo();
+ activationFailed.sessionId = 1543;
+ activationFailed.isActivationFailed = true;
+
+ ApexSessionInfo activated = new ApexSessionInfo();
+ activated.sessionId = 101;
+ activated.isActivated = true;
+
+ ApexSessionInfo staged = new ApexSessionInfo();
+ staged.sessionId = 57;
+ staged.isActivationFailed = true;
+
+ SparseArray<ApexSessionInfo> apexdSessions = new SparseArray<>();
+ apexdSessions.put(1543, activationFailed);
+ apexdSessions.put(101, activated);
+ apexdSessions.put(57, staged);
+ when(mApexManager.getSessions()).thenReturn(apexdSessions);
+
+ List<StagingManager.StagedSession> sessions = new ArrayList<>();
+ sessions.add(apkSession);
+ sessions.add(apexSession1);
+ sessions.add(apexSession2);
+ sessions.add(apexSession3);
+ sessions.add(apexSession4);
+
+ mStagingManager.restoreSessions(sessions, false);
+
+ // Validate checkpoint was aborted.
+ verify(mStorageManager, times(1)).abortChanges(eq("abort-staged-install"), eq(false));
+ }
+
+ @Test
+ public void restoreSessions_apexSessionInImpossibleState_failsAllSessions() throws Exception {
+ FakeStagedSession apkSession = new FakeStagedSession(239);
+ apkSession.setCommitted(true);
+ apkSession.setSessionReady();
+
+ FakeStagedSession apexSession = new FakeStagedSession(1543);
+ apexSession.setCommitted(true);
+ apexSession.setIsApex(true);
+ apexSession.setSessionReady();
+
+ ApexSessionInfo impossible = new ApexSessionInfo();
+ impossible.sessionId = 1543;
+
+ SparseArray<ApexSessionInfo> apexdSessions = new SparseArray<>();
+ apexdSessions.put(1543, impossible);
+ when(mApexManager.getSessions()).thenReturn(apexdSessions);
+
+ List<StagingManager.StagedSession> sessions = new ArrayList<>();
+ sessions.add(apkSession);
+ sessions.add(apexSession);
+
+ mStagingManager.restoreSessions(sessions, false);
+
+ // Validate checkpoint wasn't aborted.
+ verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
+
+ assertThat(apexSession.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apexSession.getErrorMessage()).isEqualTo("Impossible state");
+
+ assertThat(apkSession.getErrorCode())
+ .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+ assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
+ }
+
+ private StagingManager.StagedSession createSession(int sessionId, String packageName,
+ long committedMillis) {
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ params.isStaged = true;
+
+ InstallSource installSource = InstallSource.create("testInstallInitiator",
+ "testInstallOriginator", "testInstaller", "testAttributionTag");
+
+ PackageInstallerSession session = new PackageInstallerSession(
+ /* callback */ null,
+ /* context */ null,
+ /* pm */ null,
+ /* sessionProvider */ null,
+ /* looper */ BackgroundThread.getHandler().getLooper(),
+ /* stagingManager */ null,
+ /* sessionId */ sessionId,
+ /* userId */ 456,
+ /* installerUid */ -1,
+ /* installSource */ installSource,
+ /* sessionParams */ params,
+ /* createdMillis */ 0L,
+ /* committedMillis */ committedMillis,
+ /* stageDir */ mTmpDir,
+ /* stageCid */ null,
+ /* files */ null,
+ /* checksums */ null,
+ /* prepared */ true,
+ /* committed */ true,
+ /* destroyed */ false,
+ /* sealed */ false, // Setting to true would trigger some PM logic.
+ /* childSessionIds */ null,
+ /* parentSessionId */ -1,
+ /* isReady */ false,
+ /* isFailed */ false,
+ /* isApplied */false,
+ /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.STAGED_SESSION_NO_ERROR,
+ /* stagedSessionErrorMessage */ "no error");
+
+ StagingManager.StagedSession stagedSession = spy(session.mStagedSession);
+ doReturn(packageName).when(stagedSession).getPackageName();
+ doAnswer(invocation -> {
+ Predicate<StagingManager.StagedSession> filter = invocation.getArgument(0);
+ return filter.test(stagedSession);
+ }).when(stagedSession).sessionContains(any());
+ return stagedSession;
+ }
+
+ private static final class FakeStagedSession implements StagingManager.StagedSession {
+ private final int mSessionId;
+ private boolean mIsApex = false;
+ private boolean mIsCommitted = false;
+ private boolean mIsReady = false;
+ private boolean mIsApplied = false;
+ private boolean mIsFailed = false;
+ private @StagedSessionErrorCode int mErrorCode = -1;
+ private String mErrorMessage;
+ private boolean mIsDestroyed = false;
+ private int mParentSessionId = -1;
+ private String mPackageName;
+ private boolean mIsAbandonded = false;
+ private boolean mPreRebootVerificationStarted = false;
+ private final List<StagingManager.StagedSession> mChildSessions = new ArrayList<>();
+
+ private FakeStagedSession(int sessionId) {
+ mSessionId = sessionId;
+ }
+
+ private void setParentSessionId(int parentSessionId) {
+ mParentSessionId = parentSessionId;
+ }
+
+ private void setCommitted(boolean isCommitted) {
+ mIsCommitted = isCommitted;
+ }
+
+ private void setIsApex(boolean isApex) {
+ mIsApex = isApex;
+ }
+
+ private void setDestroyed(boolean isDestroyed) {
+ mIsDestroyed = isDestroyed;
+ }
+
+ private void setPackageName(String packageName) {
+ mPackageName = packageName;
+ }
+
+ private boolean isAbandonded() {
+ return mIsAbandonded;
+ }
+
+ private boolean hasPreRebootVerificationStarted() {
+ return mPreRebootVerificationStarted;
+ }
+
+ private FakeStagedSession addChildSession(FakeStagedSession session) {
+ mChildSessions.add(session);
+ session.setParentSessionId(sessionId());
+ return this;
+ }
+
+ private @StagedSessionErrorCode int getErrorCode() {
+ return mErrorCode;
+ }
+
+ private String getErrorMessage() {
+ return mErrorMessage;
+ }
+
+ @Override
+ public boolean isMultiPackage() {
+ return !mChildSessions.isEmpty();
+ }
+
+ @Override
+ public boolean isApexSession() {
+ return mIsApex;
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return mIsCommitted;
+ }
+
+ @Override
+ public boolean isInTerminalState() {
+ return isSessionApplied() || isSessionFailed();
+ }
+
+ @Override
+ public boolean isDestroyed() {
+ return mIsDestroyed;
+ }
+
+ @Override
+ public boolean isSessionReady() {
+ return mIsReady;
+ }
+
+ @Override
+ public boolean isSessionApplied() {
+ return mIsApplied;
+ }
+
+ @Override
+ public boolean isSessionFailed() {
+ return mIsFailed;
+ }
+
+ @Override
+ public List<StagingManager.StagedSession> getChildSessions() {
+ return mChildSessions;
+ }
+
+ @Override
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ public int getParentSessionId() {
+ return mParentSessionId;
+ }
+
+ @Override
+ public int sessionId() {
+ return mSessionId;
+ }
+
+ @Override
+ public PackageInstaller.SessionParams sessionParams() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean sessionContains(Predicate<StagingManager.StagedSession> filter) {
+ return filter.test(this);
+ }
+
+ @Override
+ public boolean containsApkSession() {
+ Preconditions.checkState(!hasParentSessionId(), "Child session");
+ if (!isMultiPackage()) {
+ return !isApexSession();
+ }
+ for (StagingManager.StagedSession session : mChildSessions) {
+ if (!session.isApexSession()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean containsApexSession() {
+ Preconditions.checkState(!hasParentSessionId(), "Child session");
+ if (!isMultiPackage()) {
+ return isApexSession();
+ }
+ for (StagingManager.StagedSession session : mChildSessions) {
+ if (session.isApexSession()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setSessionReady() {
+ mIsReady = true;
+ }
+
+ @Override
+ public void setSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage) {
+ Preconditions.checkState(!mIsApplied, "Already marked as applied");
+ mIsFailed = true;
+ mErrorCode = errorCode;
+ mErrorMessage = errorMessage;
+ }
+
+ @Override
+ public void setSessionApplied() {
+ Preconditions.checkState(!mIsFailed, "Already marked as failed");
+ mIsApplied = true;
+ }
+
+ @Override
+ public void installSession(IntentSender statusReceiver) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean hasParentSessionId() {
+ return mParentSessionId != -1;
+ }
+
+ @Override
+ public long getCommittedMillis() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void abandon() {
+ mIsAbandonded = true;
+ }
+
+ @Override
+ public boolean notifyStartPreRebootVerification() {
+ mPreRebootVerificationStarted = true;
+ // TODO(ioffe): change to true when tests for pre-reboot verification are added.
+ return false;
+ }
+
+ @Override
+ public void notifyEndPreRebootVerification() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void verifySession() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index af11fe1..b98f025 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -23,7 +23,6 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
-import android.app.backup.BackupAgent;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
@@ -31,7 +30,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import com.android.internal.backup.IBackupTransport;
import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
@@ -58,7 +56,6 @@
@Mock IBackupObserver mBackupObserver;
@Mock PackageManager mPackageManager;
@Mock TransportClient mTransportClient;
- @Mock IBackupTransport mBackupTransport;
@Mock BackupEligibilityRules mBackupEligibilityRules;
@@ -135,29 +132,6 @@
assertThat(params.mBackupEligibilityRules).isEqualTo(mBackupEligibilityRules);
}
- @Test
- public void testGetOperationTypeFromTransport_returnsMigrationForMigrationTransport()
- throws Exception {
- when(mTransportClient.connectOrThrow(any())).thenReturn(mBackupTransport);
- when(mBackupTransport.getTransportFlags()).thenReturn(
- BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER);
-
- int operationType = mService.getOperationTypeFromTransport(mTransportClient);
-
- assertThat(operationType).isEqualTo(OperationType.MIGRATION);
- }
-
- @Test
- public void testGetOperationTypeFromTransport_returnsBackupByDefault()
- throws Exception {
- when(mTransportClient.connectOrThrow(any())).thenReturn(mBackupTransport);
- when(mBackupTransport.getTransportFlags()).thenReturn(0);
-
- int operationType = mService.getOperationTypeFromTransport(mTransportClient);
-
- assertThat(operationType).isEqualTo(OperationType.BACKUP);
- }
-
private static PackageInfo getPackageInfo(String packageName) {
PackageInfo packageInfo = new PackageInfo();
packageInfo.applicationInfo = new ApplicationInfo();
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index 353ac4b..f9b25d9 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -39,6 +39,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -51,7 +52,7 @@
private static final String TAG = "WorkerCountTrackerTest";
private static final double[] EQUAL_PROBABILITY_CDF =
- buildCdf(1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES,
+ buildWorkTypeCdf(1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES,
1.0 / NUM_WORK_TYPES);
private Random mRandom;
@@ -64,18 +65,19 @@
}
@NonNull
- private static double[] buildCdf(double pTop, double pEj, double pBg, double pBgUser) {
- double[] cdf = new double[JobConcurrencyManager.NUM_WORK_TYPES];
+ private static double[] buildWorkTypeCdf(double pTop, double pEj, double pBg, double pBgUser) {
+ return buildCdf(pTop, pEj, pBg, pBgUser);
+ }
+
+ @NonNull
+ private static double[] buildCdf(double... probs) {
+ double[] cdf = new double[probs.length];
double sum = 0;
- sum += pTop;
- cdf[0] = sum;
- sum += pEj;
- cdf[1] = sum;
- sum += pBg;
- cdf[2] = sum;
- sum += pBgUser;
- cdf[3] = sum;
+ for (int i = 0; i < probs.length; ++i) {
+ sum += probs[i];
+ cdf[i] = sum;
+ }
if (Double.compare(1, sum) != 0) {
throw new IllegalArgumentException("probabilities don't sum to one: " + sum);
@@ -83,25 +85,30 @@
return cdf;
}
- @JobConcurrencyManager.WorkType
- static int getRandomWorkType(double[] cdf, double rand) {
+ static int getRandomIndex(double[] cdf, double rand) {
for (int i = cdf.length - 1; i >= 0; --i) {
if (rand < cdf[i] && (i == 0 || rand > cdf[i - 1])) {
- switch (i) {
- case 0:
- return WORK_TYPE_TOP;
- case 1:
- return WORK_TYPE_EJ;
- case 2:
- return WORK_TYPE_BG;
- case 3:
- return WORK_TYPE_BGUSER;
- default:
- throw new IllegalStateException("Unknown work type");
- }
+ return i;
}
}
- throw new IllegalStateException("Couldn't pick random work type");
+ throw new IllegalStateException("Couldn't pick random index");
+ }
+
+ @JobConcurrencyManager.WorkType
+ static int getRandomWorkType(double[] cdf, double rand) {
+ final int index = getRandomIndex(cdf, rand);
+ switch (index) {
+ case 0:
+ return WORK_TYPE_TOP;
+ case 1:
+ return WORK_TYPE_EJ;
+ case 2:
+ return WORK_TYPE_BG;
+ case 3:
+ return WORK_TYPE_BGUSER;
+ default:
+ throw new IllegalStateException("Unknown work type");
+ }
}
/**
@@ -110,25 +117,59 @@
class Jobs {
public final SparseIntArray running = new SparseIntArray();
public final SparseIntArray pending = new SparseIntArray();
+ public final List<Integer> pendingMultiTypes = new ArrayList<>();
- public void maybeEnqueueJobs(double probStart, double[] typeCdf) {
+ /**
+ * @param probStart Probability of starting a job
+ * @param typeCdf The CDF representing the probability of each work type
+ * @param numTypesCdf The CDF representing the probability of a job having X different
+ * work types. Each index i represents i+1 work types (ie. index 0 = 1
+ * work type, index 3 = 4 work types).
+ */
+ public void maybeEnqueueJobs(double probStart, double[] typeCdf, double[] numTypesCdf) {
+ assertThat(numTypesCdf.length).isAtMost(NUM_WORK_TYPES);
+ assertThat(numTypesCdf.length).isAtLeast(1);
+
while (mRandom.nextDouble() < probStart) {
- final int workType = getRandomWorkType(typeCdf, mRandom.nextDouble());
- pending.put(workType, pending.get(workType) + 1);
+ final int numTypes = getRandomIndex(numTypesCdf, mRandom.nextDouble()) + 1;
+ int types = WORK_TYPE_NONE;
+ for (int i = 0; i < numTypes; ++i) {
+ types |= getRandomWorkType(typeCdf, mRandom.nextDouble());
+ }
+ addPending(types, 1);
}
}
- public void maybeFinishJobs(double probStop) {
- for (int i = running.get(WORK_TYPE_BG); i > 0; i--) {
- if (mRandom.nextDouble() < probStop) {
- running.put(WORK_TYPE_BG, running.get(WORK_TYPE_BG) - 1);
- mWorkCountTracker.onJobFinished(WORK_TYPE_BG);
+ void addPending(int allWorkTypes, int num) {
+ for (int n = 0; n < num; ++n) {
+ for (int i = 0; i < 32; ++i) {
+ final int type = 1 << i;
+ if ((allWorkTypes & type) != 0) {
+ pending.put(type, pending.get(type) + 1);
+ }
+ }
+ pendingMultiTypes.add(allWorkTypes);
+ }
+ }
+
+ void removePending(int allWorkTypes) {
+ for (int i = 0; i < 32; ++i) {
+ final int type = 1 << i;
+ if ((allWorkTypes & type) != 0) {
+ pending.put(type, pending.get(type) - 1);
}
}
- for (int i = running.get(WORK_TYPE_TOP); i > 0; i--) {
- if (mRandom.nextDouble() < probStop) {
- running.put(WORK_TYPE_TOP, running.get(WORK_TYPE_TOP) - 1);
- mWorkCountTracker.onJobFinished(WORK_TYPE_TOP);
+ pendingMultiTypes.remove(Integer.valueOf(allWorkTypes));
+ }
+
+ public void maybeFinishJobs(double probStop) {
+ for (int i = running.size() - 1; i >= 0; --i) {
+ final int workType = running.keyAt(i);
+ for (int c = running.valueAt(i); c > 0; --c) {
+ if (mRandom.nextDouble() < probStop) {
+ running.put(workType, running.get(workType) - 1);
+ mWorkCountTracker.onJobFinished(workType);
+ }
}
}
}
@@ -171,6 +212,15 @@
return false;
}
+ private int getPendingMultiType(Jobs jobs, @JobConcurrencyManager.WorkType int workType) {
+ for (int multiType : jobs.pendingMultiTypes) {
+ if ((multiType & workType) != 0) {
+ return multiType;
+ }
+ }
+ throw new IllegalStateException("No pending multi type with work type: " + workType);
+ }
+
private void startPendingJobs(Jobs jobs) {
while (hasStartablePendingJob(jobs)) {
final int startingWorkType =
@@ -178,9 +228,10 @@
if (jobs.pending.get(startingWorkType) > 0
&& mWorkCountTracker.canJobStart(startingWorkType) != WORK_TYPE_NONE) {
- jobs.pending.put(startingWorkType, jobs.pending.get(startingWorkType) - 1);
+ final int pendingMultiType = getPendingMultiType(jobs, startingWorkType);
+ jobs.removePending(pendingMultiType);
jobs.running.put(startingWorkType, jobs.running.get(startingWorkType) + 1);
- mWorkCountTracker.stageJob(startingWorkType);
+ mWorkCountTracker.stageJob(startingWorkType, pendingMultiType);
mWorkCountTracker.onJobStarted(startingWorkType);
}
}
@@ -192,12 +243,17 @@
private void checkRandom(Jobs jobs, int numTests, int totalMax,
@NonNull List<Pair<Integer, Integer>> minLimits,
@NonNull List<Pair<Integer, Integer>> maxLimits,
- double probStart, double[] typeCdf, double probStop) {
+ double probStart, double[] typeCdf, double[] numTypesCdf, double probStop) {
+ int minExpected = 0;
+ for (Pair<Integer, Integer> minLimit : minLimits) {
+ minExpected = Math.min(minLimit.second, minExpected);
+ }
for (int i = 0; i < numTests; i++) {
jobs.maybeFinishJobs(probStop);
- jobs.maybeEnqueueJobs(probStart, typeCdf);
+ jobs.maybeEnqueueJobs(probStart, typeCdf, numTypesCdf);
recount(jobs, totalMax, minLimits, maxLimits);
+ final int numPending = jobs.pendingMultiTypes.size();
startPendingJobs(jobs);
int totalRunning = 0;
@@ -209,6 +265,7 @@
totalRunning += numRunning;
}
assertThat(totalRunning).isAtMost(totalMax);
+ assertThat(totalRunning).isAtLeast(Math.min(minExpected, numPending));
for (Pair<Integer, Integer> maxLimit : maxLimits) {
assertWithMessage("Work type " + maxLimit.first + " is running too many jobs")
.that(jobs.running.get(maxLimit.first)).isAtMost(maxLimit.second);
@@ -233,7 +290,7 @@
final double probStart = 0.1;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
- EQUAL_PROBABILITY_CDF, probStop);
+ EQUAL_PROBABILITY_CDF, EQUAL_PROBABILITY_CDF, probStop);
}
@Test
@@ -246,10 +303,12 @@
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
final double probStop = 0.5;
- final double[] cdf = buildCdf(0.5, 0, 0.5, 0);
+ final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0);
+ final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -262,10 +321,12 @@
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.5;
- final double[] cdf = buildCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+ final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+ final double[] numTypesCdf = buildCdf(.75, .2, .05);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -278,10 +339,12 @@
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
final double probStop = 0.5;
- final double[] cdf = buildCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+ final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+ final double[] numTypesCdf = buildCdf(.05, .95);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -294,10 +357,12 @@
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.5;
- final double[] cdf = buildCdf(0.1, 0, 0.8, .1);
+ final double[] cdf = buildWorkTypeCdf(0.1, 0, 0.8, .1);
+ final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -310,10 +375,12 @@
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.5;
- final double[] cdf = buildCdf(0.9, 0, 0.1, 0);
+ final double[] cdf = buildWorkTypeCdf(0.9, 0, 0.1, 0);
+ final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -326,10 +393,12 @@
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildCdf(0.1, 0, 0.1, .8);
+ final double[] cdf = buildWorkTypeCdf(0.1, 0, 0.1, .8);
+ final double[] numTypesCdf = buildCdf(0.5, 0.5);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -343,10 +412,12 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.4;
- final double[] cdf = buildCdf(0.9, 0, 0.05, 0.05);
+ final double[] cdf = buildWorkTypeCdf(0.9, 0, 0.05, 0.05);
+ final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -360,10 +431,12 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.5;
- final double[] cdf = buildCdf(0, 0, 0.5, 0.5);
+ final double[] cdf = buildWorkTypeCdf(0, 0, 0.5, 0.5);
+ final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -377,10 +450,12 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.5;
- final double[] cdf = buildCdf(0, 0, 0.1, 0.9);
+ final double[] cdf = buildWorkTypeCdf(0, 0, 0.1, 0.9);
+ final double[] numTypesCdf = buildCdf(0.9, 0.1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -394,10 +469,12 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.5;
- final double[] cdf = buildCdf(0, 0, 0.9, 0.1);
+ final double[] cdf = buildWorkTypeCdf(0, 0, 0.9, 0.1);
+ final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -410,10 +487,12 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildCdf(0.5, 0.5, 0, 0);
+ final double[] cdf = buildWorkTypeCdf(0.5, 0.5, 0, 0);
+ final double[] numTypesCdf = buildCdf(0.1, 0.7, 0.2);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -430,10 +509,11 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1));
final double probStop = 0.01;
+ final double[] numTypesCdf = buildCdf(0, 0.05, 0.05, 0.9);
final double probStart = 0.99;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
- EQUAL_PROBABILITY_CDF, probStop);
+ EQUAL_PROBABILITY_CDF, numTypesCdf, probStop);
}
@Test
@@ -446,10 +526,12 @@
List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildCdf(.1, 0.5, 0.35, 0.05);
+ final double[] cdf = buildWorkTypeCdf(.1, 0.5, 0.35, 0.05);
+ final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
@Test
@@ -464,10 +546,12 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildCdf(0.01, 0.49, 0.1, 0.4);
+ final double[] cdf = buildWorkTypeCdf(0.01, 0.49, 0.1, 0.4);
+ final double[] numTypesCdf = buildCdf(0.7, 0.3);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
}
/** Used by the following tests */
@@ -483,7 +567,7 @@
jobs.running.put(run.first, run.second);
}
for (Pair<Integer, Integer> pend : pending) {
- jobs.pending.put(pend.first, pend.second);
+ jobs.addPending(pend.first, pend.second);
}
recount(jobs, totalMax, minLimits, maxLimits);
@@ -651,14 +735,32 @@
Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
/* resPen */ List.of(
Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2)));
+
+ // Test multi-types
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /* run */ List.of(),
+ /* pen */ List.of(
+ // 2 of these as TOP, 1 as EJ
+ Pair.create(WORK_TYPE_TOP | WORK_TYPE_EJ, 3),
+ // 1 as EJ, 2 as BG
+ Pair.create(WORK_TYPE_EJ | WORK_TYPE_BG, 3),
+ Pair.create(WORK_TYPE_BG, 4),
+ Pair.create(WORK_TYPE_BGUSER, 1)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2),
+ Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
+ /* resPen */ List.of(
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)));
}
/** Tests that the counter updates properly when jobs are stopped. */
@Test
public void testJobLifecycleLoop() {
final Jobs jobs = new Jobs();
- jobs.pending.put(WORK_TYPE_TOP, 11);
- jobs.pending.put(WORK_TYPE_BG, 10);
+ jobs.addPending(WORK_TYPE_TOP, 11);
+ jobs.addPending(WORK_TYPE_BG, 10);
final int totalMax = 6;
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 1));
@@ -729,4 +831,149 @@
assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(0);
assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(3);
}
+
+ /** Tests that the counter updates properly when jobs are stopped. */
+ @Test
+ public void testJobLifecycleLoop_Multitype() {
+ final Jobs jobs = new Jobs();
+ jobs.addPending(WORK_TYPE_TOP, 6); // a
+ jobs.addPending(WORK_TYPE_TOP | WORK_TYPE_EJ, 5); // b
+ jobs.addPending(WORK_TYPE_BG, 10); // c
+
+ final int totalMax = 8;
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1));
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5));
+
+ recount(jobs, totalMax, minLimits, maxLimits);
+
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(11);
+ assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(5);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(10);
+
+ startPendingJobs(jobs);
+
+ assertThat(jobs.running.get(WORK_TYPE_TOP)).isEqualTo(6);
+ assertThat(jobs.running.get(WORK_TYPE_EJ)).isEqualTo(1);
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(4);
+ // Since starting happens in random order, all EJs could have run first.
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(9);
+
+ // Stop all jobs
+ jobs.maybeFinishJobs(1);
+
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_TOP)).isEqualTo(WORK_TYPE_TOP);
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_EJ)).isEqualTo(WORK_TYPE_EJ);
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_BG)).isEqualTo(WORK_TYPE_BG);
+
+ startPendingJobs(jobs);
+
+ assertThat(jobs.running.get(WORK_TYPE_TOP) + jobs.running.get(WORK_TYPE_EJ)).isEqualTo(4);
+ // Depending on the order jobs start, we may run all TOP/EJ combos as TOP and reserve a slot
+ // for EJ, which would reduce BG count to 3 instead of 4.
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isAtLeast(3);
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isAtMost(4);
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(0);
+ assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(0);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtLeast(5);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtMost(6);
+
+ // Stop only a bg job and make sure the counter only allows another bg job to start.
+ jobs.running.put(WORK_TYPE_BG, jobs.running.get(WORK_TYPE_BG) - 1);
+ mWorkCountTracker.onJobFinished(WORK_TYPE_BG);
+
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_TOP)).isEqualTo(WORK_TYPE_NONE);
+ // Depending on the order jobs start, we may run all TOP/EJ combos as TOP and reserve a slot
+ // for EJ, which would reduce BG count to 3 instead of 4.
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_BG)).isEqualTo(WORK_TYPE_BG);
+
+ startPendingJobs(jobs);
+
+ assertThat(jobs.running.get(WORK_TYPE_TOP) + jobs.running.get(WORK_TYPE_EJ)).isEqualTo(4);
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isAtLeast(3);
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isAtMost(4);
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(0);
+ assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(0);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtLeast(4);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtMost(5);
+ }
+
+ /** Tests that the counter updates properly when jobs are stopped. */
+ @Test
+ public void testJobLifecycleLoop_Multitype_RandomOrder() {
+ final Jobs jobs = new Jobs();
+ SparseIntArray multiToCount = new SparseIntArray();
+ multiToCount.put(WORK_TYPE_TOP, 6); // a
+ multiToCount.put(WORK_TYPE_TOP | WORK_TYPE_EJ, 5); // b
+ multiToCount.put(WORK_TYPE_EJ | WORK_TYPE_BG, 5); // c
+ multiToCount.put(WORK_TYPE_BG, 5); // d
+ while (multiToCount.size() > 0) {
+ final int index = mRandom.nextInt(multiToCount.size());
+ final int count = multiToCount.valueAt(index);
+ jobs.addPending(multiToCount.keyAt(index), 1);
+ if (count <= 1) {
+ multiToCount.removeAt(index);
+ } else {
+ multiToCount.put(multiToCount.keyAt(index), count - 1);
+ }
+ }
+
+ final int totalMax = 8;
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1));
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5));
+
+ recount(jobs, totalMax, minLimits, maxLimits);
+
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(11);
+ assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(10);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(10);
+
+ startPendingJobs(jobs);
+
+ // Random order, but we should have 6 TOP, 1 EJ, and 1 BG running.
+ assertThat(jobs.running.get(WORK_TYPE_TOP)).isEqualTo(6);
+ assertThat(jobs.running.get(WORK_TYPE_EJ)).isEqualTo(1);
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(4);
+ // Can't equate pending EJ since some could be running as TOP and BG
+ assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(2);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(9);
+
+ // Stop all jobs
+ jobs.maybeFinishJobs(1);
+
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_TOP)).isEqualTo(WORK_TYPE_TOP);
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_EJ)).isEqualTo(WORK_TYPE_EJ);
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_BG)).isEqualTo(WORK_TYPE_BG);
+
+ startPendingJobs(jobs);
+
+ // Random order, but we should have 4 TOP, 1 EJ, and 1 BG running.
+ assertThat(jobs.running.get(WORK_TYPE_TOP)).isAtLeast(1);
+ assertThat(jobs.running.get(WORK_TYPE_EJ)).isAtLeast(1);
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
+ // At this point, all TOP should be running (or have already run).
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(0);
+ assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(2);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(5);
+
+ // Stop only a bg job and make sure the counter only allows another bg job to start.
+ jobs.running.put(WORK_TYPE_BG, jobs.running.get(WORK_TYPE_BG) - 1);
+ mWorkCountTracker.onJobFinished(WORK_TYPE_BG);
+
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_TOP)).isEqualTo(WORK_TYPE_NONE);
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_EJ)).isEqualTo(WORK_TYPE_NONE);
+ assertThat(mWorkCountTracker.canJobStart(WORK_TYPE_BG)).isEqualTo(WORK_TYPE_BG);
+
+ startPendingJobs(jobs);
+
+ assertThat(jobs.running.get(WORK_TYPE_TOP)).isAtLeast(1);
+ assertThat(jobs.running.get(WORK_TYPE_EJ)).isAtLeast(1);
+ assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
+ assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(0);
+ assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(2);
+ assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(4);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index a4ba4c8..a896f1b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -43,6 +43,7 @@
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
import android.hardware.rebootescrow.IRebootEscrow;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserManager;
@@ -155,6 +156,11 @@
}
@Override
+ void post(Handler handler, Runnable runnable) {
+ runnable.run();
+ }
+
+ @Override
public UserManager getUserManager() {
return mUserManager;
}
@@ -369,7 +375,7 @@
@Test
public void loadRebootEscrowDataIfAvailable_NothingAvailable_Success() throws Exception {
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
}
@Test
@@ -401,7 +407,7 @@
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -435,7 +441,7 @@
when(mServiceConnection.unwrap(any(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mServiceConnection).unwrap(any(), anyLong());
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -466,7 +472,7 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
verify(mInjected, never()).reportMetric(anyBoolean());
}
@@ -493,7 +499,7 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mInjected, never()).reportMetric(anyBoolean());
}
@@ -527,7 +533,7 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mInjected).reportMetric(eq(true));
}
@@ -557,7 +563,7 @@
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertFalse(metricsSuccessCaptor.getValue());
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
index bc1e025..28b737b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
@@ -30,6 +30,7 @@
import android.content.Context;
import android.content.ContextWrapper;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
@@ -42,7 +43,6 @@
import org.mockito.stubbing.Answer;
import java.io.File;
-import java.io.IOException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
@@ -130,7 +130,7 @@
@Test
public void getAndClearRebootEscrowKey_ServiceConnectionException_failure() throws Exception {
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())).thenAnswer(mFakeEncryption);
- doThrow(IOException.class).when(mServiceConnection).unwrap(any(), anyLong());
+ doThrow(RemoteException.class).when(mServiceConnection).unwrap(any(), anyLong());
assertTrue(mRebootEscrowProvider.hasRebootEscrowSupport());
mRebootEscrowProvider.storeRebootEscrowKey(mRebootEscrowKey, mKeyStoreEncryptionKey);
diff --git a/services/tests/servicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/StagingManagerTest.java
deleted file mode 100644
index 79935c2..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/StagingManagerTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.content.Context;
-import android.content.pm.PackageInstaller;
-import android.os.storage.StorageManager;
-import android.platform.test.annotations.Presubmit;
-
-import com.android.internal.os.BackgroundThread;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.util.function.Predicate;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-
-@Presubmit
-@RunWith(JUnit4.class)
-public class StagingManagerTest {
- @Rule
- public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
-
- private File mTmpDir;
- private StagingManager mStagingManager;
-
- @Before
- public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
- StorageManager storageManager = Mockito.mock(StorageManager.class);
- Context context = Mockito.mock(Context.class);
- when(storageManager.isCheckpointSupported()).thenReturn(true);
- when(context.getSystemService(eq(Context.POWER_SERVICE))).thenReturn(null);
- when(context.getSystemService(eq(Context.STORAGE_SERVICE))).thenReturn(storageManager);
-
- mTmpDir = mTemporaryFolder.newFolder("StagingManagerTest");
- mStagingManager = new StagingManager(context, null);
- }
-
- /**
- * Tests that sessions committed later shouldn't cause earlier ones to fail the overlapping
- * check.
- */
- @Test
- public void checkNonOverlappingWithStagedSessions_laterSessionShouldNotFailEarlierOnes()
- throws Exception {
- // Create 2 sessions with overlapping packages
- StagingManager.StagedSession session1 = createSession(111, "com.foo", 1);
- StagingManager.StagedSession session2 = createSession(222, "com.foo", 2);
-
- mStagingManager.createSession(session1);
- mStagingManager.createSession(session2);
- // Session1 should not fail in spite of the overlapping packages
- mStagingManager.checkNonOverlappingWithStagedSessions(session1);
- // Session2 should fail due to overlapping packages
- assertThrows(PackageManagerException.class,
- () -> mStagingManager.checkNonOverlappingWithStagedSessions(session2));
- }
-
- private StagingManager.StagedSession createSession(int sessionId, String packageName,
- long committedMillis) {
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- params.isStaged = true;
-
- InstallSource installSource = InstallSource.create("testInstallInitiator",
- "testInstallOriginator", "testInstaller", "testAttributionTag");
-
- PackageInstallerSession session = new PackageInstallerSession(
- /* callback */ null,
- /* context */ null,
- /* pm */ null,
- /* sessionProvider */ null,
- /* looper */ BackgroundThread.getHandler().getLooper(),
- /* stagingManager */ null,
- /* sessionId */ sessionId,
- /* userId */ 456,
- /* installerUid */ -1,
- /* installSource */ installSource,
- /* sessionParams */ params,
- /* createdMillis */ 0L,
- /* committedMillis */ committedMillis,
- /* stageDir */ mTmpDir,
- /* stageCid */ null,
- /* files */ null,
- /* checksums */ null,
- /* prepared */ true,
- /* committed */ true,
- /* destroyed */ false,
- /* sealed */ false, // Setting to true would trigger some PM logic.
- /* childSessionIds */ null,
- /* parentSessionId */ -1,
- /* isReady */ false,
- /* isFailed */ false,
- /* isApplied */false,
- /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.STAGED_SESSION_NO_ERROR,
- /* stagedSessionErrorMessage */ "no error");
-
- StagingManager.StagedSession stagedSession = spy(session.mStagedSession);
- doReturn(packageName).when(stagedSession).getPackageName();
- doAnswer(invocation -> {
- Predicate<StagingManager.StagedSession> filter = invocation.getArgument(0);
- return filter.test(stagedSession);
- }).when(stagedSession).sessionContains(any());
- return stagedSession;
- }
-}
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/OWNERS b/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index ec28baf..07475e9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1686,6 +1686,11 @@
}
@Override
+ protected void ensureFilters(ServiceInfo si, int userId) {
+
+ }
+
+ @Override
protected void loadDefaultsFromConfig() {
mDefaultComponents.addAll(mDefaults);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index afcf08ef..80a046a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -15,6 +15,11 @@
*/
package com.android.server.notification;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+
+import static com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -27,11 +32,14 @@
import android.content.ComponentName;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.VersionedPackage;
+import android.os.Bundle;
import android.service.notification.NotificationListenerFilter;
+import android.service.notification.NotificationListenerService;
import android.util.ArraySet;
import android.util.Pair;
+import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -47,8 +55,6 @@
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.List;
public class NotificationListenersTest extends UiServiceTestCase {
@@ -80,22 +86,21 @@
@Test
public void testReadExtraTag() throws Exception {
- String xml = "<req_listeners>"
+ String xml = "<" + TAG_REQUESTED_LISTENERS+ ">"
+ "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">"
+ "<allowed types=\"7\" />"
- + "<disallowed pkgs=\"\" />"
+ "</listener>"
+ "<listener component=\"" + mCn2.flattenToString() + "\" user=\"10\">"
+ "<allowed types=\"4\" />"
- + "<disallowed pkgs=\"something\" />"
+ + "<disallowed pkg=\"pkg1\" uid=\"243\"/>"
+ "</listener>"
- + "</req_listeners>";
+ + "</" + TAG_REQUESTED_LISTENERS + ">";
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
- mListeners.readExtraTag("req_listeners", parser);
+ mListeners.readExtraTag(TAG_REQUESTED_LISTENERS, parser);
validateListenersFromXml();
}
@@ -103,8 +108,9 @@
@Test
public void testWriteExtraTag() throws Exception {
NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
NotificationListenerFilter nlf2 =
- new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
@@ -134,16 +140,18 @@
assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes())
.isEqualTo(4);
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10))
.getDisallowedPackages())
- .contains("something");
+ .contains(a1);
}
@Test
public void testOnUserRemoved() {
NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
NotificationListenerFilter nlf2 =
- new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
@@ -155,58 +163,68 @@
}
@Test
- public void testOnUserUnlocked() {
- // one exists already, say from xml
- NotificationListenerFilter nlf =
- new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
- mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf);
-
- // new service exists or backfilling on upgrade to S
+ public void testEnsureFilters_newServiceNoMetadata() {
ServiceInfo si = new ServiceInfo();
- si.permission = mListeners.getConfig().bindPermission;
+ si.packageName = "new2";
+ si.name = "comp2";
+
+ mListeners.ensureFilters(si, 0);
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))).isNull();
+ }
+
+ @Test
+ public void testEnsureFilters_preExisting() {
+ // one exists already, say from xml
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
+ mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf);
+ ServiceInfo siOld = new ServiceInfo();
+ siOld.packageName = mCn2.getPackageName();
+ siOld.name = mCn2.getClassName();
+
+ mListeners.ensureFilters(siOld, 0);
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))).isEqualTo(nlf);
+ }
+
+ @Test
+ public void testEnsureFilters_newServiceWithMetadata() {
+ ServiceInfo si = new ServiceInfo();
si.packageName = "new";
si.name = "comp";
- ResolveInfo ri = new ResolveInfo();
- ri.serviceInfo = si;
+ si.metaData = new Bundle();
+ si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1,2");
- // incorrect service
- ServiceInfo si2 = new ServiceInfo();
- ResolveInfo ri2 = new ResolveInfo();
- ri2.serviceInfo = si2;
- si2.packageName = "new2";
- si2.name = "comp2";
-
- List<ResolveInfo> ris = new ArrayList<>();
- ris.add(ri);
- ris.add(ri2);
-
- when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(ris);
-
- mListeners.onUserUnlocked(0);
-
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0)).getTypes())
- .isEqualTo(4);
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))
- .getDisallowedPackages())
- .contains("something");
+ mListeners.ensureFilters(si, 0);
assertThat(mListeners.getNotificationListenerFilter(
Pair.create(si.getComponentName(), 0)).getTypes())
- .isEqualTo(15);
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(si.getComponentName(), 0))
- .getDisallowedPackages())
- .isEmpty();
+ .isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING);
+ }
- assertThat(mListeners.getNotificationListenerFilter(Pair.create(si2.getComponentName(), 0)))
- .isNull();
+ @Test
+ public void testEnsureFilters_newServiceWithEmptyMetadata() {
+ ServiceInfo si = new ServiceInfo();
+ si.packageName = "new";
+ si.name = "comp";
+ si.metaData = new Bundle();
+ si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "");
+ mListeners.ensureFilters(si, 0);
+
+ assertThat(mListeners.getNotificationListenerFilter(
+ Pair.create(si.getComponentName(), 0)).getTypes())
+ .isEqualTo(0);
}
@Test
public void testOnPackageChanged() {
NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
NotificationListenerFilter nlf2 =
- new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
@@ -224,8 +242,9 @@
@Test
public void testOnPackageChanged_removing() {
NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
NotificationListenerFilter nlf2 =
- new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2);
@@ -239,4 +258,21 @@
.isEqualTo(4);
}
+ @Test
+ public void testOnPackageChanged_removingDisallowedPackage() {
+ NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ VersionedPackage a1 = new VersionedPackage("pkg1", 243);
+ NotificationListenerFilter nlf2 =
+ new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
+ mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
+ mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2);
+
+ String[] pkgs = new String[] {"pkg1"};
+ int[] uids = new int[] {243};
+ mListeners.onPackagesChanged(true, pkgs, uids);
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))
+ .getDisallowedPackages()).isEmpty();
+ }
+
}
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 e8888f4..a640509 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -464,7 +464,7 @@
// Setup managed services
when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
- when(mNlf.isPackageAllowed(anyString())).thenReturn(true);
+ when(mNlf.isPackageAllowed(any())).thenReturn(true);
when(mNlf.isPackageAllowed(null)).thenReturn(true);
when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf);
mListener = mListeners.new ManagedServiceInfo(
@@ -7307,7 +7307,7 @@
@Test
public void testIsVisibleToListener_disallowedPackage() {
- when(mNlf.isPackageAllowed(null)).thenReturn(false);
+ when(mNlf.isPackageAllowed(any())).thenReturn(false);
StatusBarNotification sbn = mock(StatusBarNotification.class);
when(sbn.getUserId()).thenReturn(10);
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
index 8ee72b5..60172a3 100644
--- a/services/usb/OWNERS
+++ b/services/usb/OWNERS
@@ -1,6 +1,5 @@
badhri@google.com
elaurent@google.com
-moltmann@google.com
albertccwang@google.com
jameswei@google.com
howardyen@google.com
\ No newline at end of file
diff --git a/telephony/java/android/telephony/RadioInterfaceCapabilities.java b/telephony/java/android/telephony/RadioInterfaceCapabilities.java
deleted file mode 100644
index 7c7eb9f..0000000
--- a/telephony/java/android/telephony/RadioInterfaceCapabilities.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.util.ArraySet;
-
-/**
- * Contains the set of supported capabilities that the Radio Interface supports on this device.
- *
- * @hide
- */
-public class RadioInterfaceCapabilities {
-
- private final ArraySet<String> mSupportedCapabilities;
-
-
- public RadioInterfaceCapabilities() {
- mSupportedCapabilities = new ArraySet<>();
- }
-
- /**
- * Marks a capability as supported
- *
- * @param capabilityName the name of the capability
- */
- public void addSupportedCapability(
- @TelephonyManager.RadioInterfaceCapability String capabilityName) {
- mSupportedCapabilities.add(capabilityName);
- }
-
- /**
- * Whether the capability is supported
- *
- * @param capabilityName the name of the capability
- */
- public boolean isSupported(String capabilityName) {
- return mSupportedCapabilities.contains(capabilityName);
- }
-}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 16ffd9e..ee3a0ef 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8491,6 +8491,11 @@
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>
+ * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
+ * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then
+ * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
+ * setPreferredNetworkTypesBitmap is used instead.
*
* @param subId the id of the subscription to set the preferred network type for.
* @param networkType the preferred network type
@@ -8524,6 +8529,11 @@
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>
+ * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
+ * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then
+ * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
+ * setPreferredNetworkTypesBitmap is used instead.
*
* @param networkTypeBitmask The bitmask of preferred network types.
* @return true on success; false on any failure.
@@ -8550,6 +8560,11 @@
* Set the allowed network types of the device. This is for carrier or privileged apps to
* enable/disable certain network types on the device. The user preferred network types should
* be set through {@link #setPreferredNetworkTypeBitmask}.
+ * <p>
+ * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
+ * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then
+ * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
+ * setPreferredNetworkTypesBitmap is used instead.
*
* @param allowedNetworkTypes The bitmask of allowed network types.
* @return true on success; false on any failure.
@@ -8624,6 +8639,11 @@
* </ol>
* This API will result in allowing an intersection of allowed network types for all reasons,
* including the configuration done through other reasons.
+ * <p>
+ * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
+ * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then
+ * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
+ * setPreferredNetworkTypesBitmap is used instead.
*
* @param reason the reason the allowed network type change is taking place
* @param allowedNetworkTypes The bitmask of allowed network types.
@@ -14861,10 +14881,24 @@
public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE =
"CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE";
+ /**
+ * Indicates whether {@link #setPreferredNetworkType}, {@link
+ * #setPreferredNetworkTypeBitmask}, {@link #setAllowedNetworkTypes} and
+ * {@link #setAllowedNetworkTypesForReason} rely on
+ * setAllowedNetworkTypesBitmap instead of setPreferredNetworkTypesBitmap on the radio
+ * interface.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String CAPABILITY_ALLOWED_NETWORK_TYPES_USED =
+ "CAPABILITY_ALLOWED_NETWORK_TYPES_USED";
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@StringDef(prefix = "CAPABILITY_", value = {
CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE,
+ CAPABILITY_ALLOWED_NETWORK_TYPES_USED,
})
public @interface RadioInterfaceCapability {}