Merge "Remove hidden connectivity method usage" into sc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index b4e167a..081163b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -121,54 +121,81 @@
private final SparseArray<UidDefaultNetworkCallback> mCurrentDefaultNetworkCallbacks =
new SparseArray<>();
private final Comparator<UidStats> mUidStatsComparator = new Comparator<UidStats>() {
- private int prioritizeExistence(int v1, int v2) {
- if (v1 > 0 && v2 > 0) {
+ private int prioritizeExistenceOver(int threshold, int v1, int v2) {
+ // Check if they're both on the same side of the threshold.
+ if ((v1 > threshold && v2 > threshold) || (v1 <= threshold && v2 <= threshold)) {
return 0;
}
- return v2 - v1;
+ // They're on opposite sides of the threshold.
+ if (v1 > threshold) {
+ return -1;
+ }
+ return 1;
}
@Override
public int compare(UidStats us1, UidStats us2) {
- // TODO: build a better prioritization scheme
- // Some things to use:
- // * Proc state
- // * IMPORTANT_WHILE_IN_FOREGROUND bit
- final int runningPriority = prioritizeExistence(us1.numRunning, us2.numRunning);
+ // Prioritize a UID ahead of another based on:
+ // 1. Already running connectivity jobs (so we don't drop the listener)
+ // 2. Waiting connectivity jobs would be ready with connectivity
+ // 3. An existing network satisfies a waiting connectivity job's requirements
+ // 4. TOP proc state
+ // 5. Existence of treat-as-EJ EJs (not just requested EJs)
+ // 6. FGS proc state
+ // 7. EJ enqueue time
+ // 8. Any other important job priorities/proc states
+ // 9. Enqueue time
+ // TODO: maybe consider number of jobs
+ // TODO: consider IMPORTANT_WHILE_FOREGROUND bit
+ final int runningPriority = prioritizeExistenceOver(0, us1.numRunning, us2.numRunning);
if (runningPriority != 0) {
return runningPriority;
}
// Prioritize any UIDs that have jobs that would be ready ahead of UIDs that don't.
- final int readyWithConnPriority =
- prioritizeExistence(us1.numReadyWithConnectivity, us2.numReadyWithConnectivity);
+ final int readyWithConnPriority = prioritizeExistenceOver(0,
+ us1.numReadyWithConnectivity, us2.numReadyWithConnectivity);
if (readyWithConnPriority != 0) {
return readyWithConnPriority;
}
// They both have jobs that would be ready. Prioritize the UIDs whose requested
// network is available ahead of UIDs that don't have their requested network available.
- final int reqAvailPriority = prioritizeExistence(
+ final int reqAvailPriority = prioritizeExistenceOver(0,
us1.numRequestedNetworkAvailable, us2.numRequestedNetworkAvailable);
if (reqAvailPriority != 0) {
return reqAvailPriority;
}
- // They both have jobs with available networks. Prioritize based on:
- // 1. (eventually) proc state
- // 2. Existence of runnable EJs (not just requested)
- // 3. Enqueue time
- // TODO: maybe consider number of jobs
- final int ejPriority = prioritizeExistence(us1.numEJs, us2.numEJs);
+ // Prioritize the top app. If neither are top apps, then use a later prioritization
+ // check.
+ final int topPriority = prioritizeExistenceOver(JobInfo.PRIORITY_TOP_APP - 1,
+ us1.basePriority, us2.basePriority);
+ if (topPriority != 0) {
+ return topPriority;
+ }
+ // They're either both TOP or both not TOP. Prioritize the app that has runnable EJs
+ // pending.
+ final int ejPriority = prioritizeExistenceOver(0, us1.numEJs, us2.numEJs);
if (ejPriority != 0) {
return ejPriority;
}
- // They both have EJs. Order them by EJ enqueue time to help provide low EJ latency.
+ // They both have runnable EJs.
+ // Prioritize an FGS+ app. If neither are FGS+ apps, then use a later prioritization
+ // check.
+ final int fgsPriority = prioritizeExistenceOver(JobInfo.PRIORITY_FOREGROUND_SERVICE - 1,
+ us1.basePriority, us2.basePriority);
+ if (fgsPriority != 0) {
+ return fgsPriority;
+ }
+ // Order them by EJ enqueue time to help provide low EJ latency.
if (us1.earliestEJEnqueueTime < us2.earliestEJEnqueueTime) {
return -1;
} else if (us1.earliestEJEnqueueTime > us2.earliestEJEnqueueTime) {
return 1;
}
+ // Order by any latent important proc states.
if (us1.basePriority != us2.basePriority) {
return us2.basePriority - us1.basePriority;
}
+ // Order by enqueue time.
if (us1.earliestEnqueueTime < us2.earliestEnqueueTime) {
return -1;
}
@@ -480,7 +507,7 @@
UidStats uidStats = mUidStats.get(uid);
if (uidStats != null && uidStats.basePriority != newPriority) {
uidStats.basePriority = newPriority;
- maybeAdjustRegisteredCallbacksLocked();
+ postAdjustCallbacks();
}
}
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index 7df0b4b..ce68447 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -25,7 +25,7 @@
}
public static final class MediaTranscodeManager.TranscodingSession {
- method public void addClientUid(int);
+ method public boolean addClientUid(int);
method public void cancel();
method @NonNull public java.util.List<java.lang.Integer> getClientUids();
method public int getErrorCode();
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index a7de602..d7e9609 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -1361,8 +1361,6 @@
private @TranscodingSessionErrorCode int mErrorCode = ERROR_NONE;
@GuardedBy("mLock")
private boolean mHasRetried = false;
- @GuardedBy("mLock")
- private @NonNull List<Integer> mClientUidList = new ArrayList<>();
// The original request that associated with this session.
private final TranscodingRequest mRequest;
@@ -1381,7 +1379,6 @@
mListenerExecutor = executor;
mListener = listener;
mRequest = request;
- mClientUidList.add(request.getClientUid());
}
/**
@@ -1532,17 +1529,31 @@
* Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could add the
* uid. Note that the permission check happens on the service side upon starting the
* transcoding. If the client does not have the permission, the transcoding will fail.
+ * @param uid the additional client uid to be added.
+ * @return true if successfully added, false otherwise.
*/
- public void addClientUid(int uid) {
+ public boolean addClientUid(int uid) {
if (uid < 0) {
throw new IllegalArgumentException("Invalid Uid");
}
- synchronized (mLock) {
- if (!mClientUidList.contains(uid)) {
- // see ag/14023202 for implementation
- mClientUidList.add(uid);
- }
+
+ // Get the client interface.
+ ITranscodingClient client = mManager.getTranscodingClient();
+ if (client == null) {
+ Log.e(TAG, "Service is dead...");
+ return false;
}
+
+ try {
+ if (!client.addClientUid(mSessionId, uid)) {
+ Log.e(TAG, "Failed to add client uid");
+ return false;
+ }
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to get client uids due to " + ex);
+ return false;
+ }
+ return true;
}
/**
@@ -1551,9 +1562,25 @@
*/
@NonNull
public List<Integer> getClientUids() {
- synchronized (mLock) {
- return mClientUidList;
+ List<Integer> uidList = new ArrayList<Integer>();
+
+ // Get the client interface.
+ ITranscodingClient client = mManager.getTranscodingClient();
+ if (client == null) {
+ Log.e(TAG, "Service is dead...");
+ return uidList;
}
+
+ try {
+ int[] clientUids = client.getClientUids(mSessionId);
+ for (int i : clientUids) {
+ uidList.add(i);
+ }
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to get client uids due to " + ex);
+ }
+
+ return uidList;
}
/**
diff --git a/api/dump_api_shas.sh b/api/dump_api_shas.sh
new file mode 100755
index 0000000..c023b31
--- /dev/null
+++ b/api/dump_api_shas.sh
@@ -0,0 +1,56 @@
+#!/bin/bash -e
+# This script dumps the git SHAs of all commits inside api tracking directories.
+# It can used by tools wanting to track API changes, and the primary original
+# purpose is to verify verify all API change SHAs have been tracked by the
+# server-side API-council tools.
+#
+# The only argument is used to specify a git commit range to filter by.
+#
+# Example invocation (API changes between O and P):
+# frameworks/base/api/dump_api_shas.sh origin/oreo-dev..origin/pie-dev
+
+set -o pipefail
+
+eecho() { echo $@ >&2 ; }
+
+if [[ $1 == *..* ]]; then
+ exclude=${1/..*}
+ include=${1/*..}
+else
+ eecho No range or invalid range specified, defaulting to all commits from HEAD.
+ exclude=
+ include=HEAD
+fi
+
+eecho -n building queryview...
+{ source build/envsetup.sh && lunch aosp_arm && m queryview; } >/dev/null 2>&1 \
+ || { eecho failed; exit 1; }
+eecho "done"
+
+# This finds the directories where the dependant java_sdk_libs are defined
+bpdirs=$(
+ bazel query --config=queryview --output=package \
+ 'kind(java_sdk_library, deps(//frameworks/base/api/..., 1))' 2>/dev/null
+ echo frameworks/base/core/api # Not a java_sdk_library.
+ echo frameworks/base/services/api # Not a java_sdk_library.
+)
+
+# Find relevant api subdirectories
+apidirs=$(
+ find $bpdirs -type f -name '*current.txt' -path '*/api/*' \
+ | xargs realpath --relative-to=$(pwd) | xargs dirname | sort | uniq
+)
+
+# Dump sorted SHAs of commits in these directories
+{ for d in $apidirs; do
+ ( cd $d
+ eecho inspecting $d
+ exclude_arg=$(test -n "$exclude" && {
+ git rev-parse -q --verify $exclude > /dev/null && echo "--not $exclude" \
+ || eecho "$d has no revision $exclude, including all commits"; } || true)
+ for f in $(find . -name '*current.txt'); do
+ git --no-pager log --pretty=format:%H --no-merges --follow $include $exclude_arg -- $f
+ echo # No trailing newline with --no-pager
+ done
+ )
+done; } | sort | uniq
diff --git a/config/OWNERS b/config/OWNERS
index 001038d..0691dbc 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -1,14 +1,8 @@
include /ZYGOTE_OWNERS
-# compat-team@ for changes to hiddenapi files
-
-per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com
-
# art-team@ manages the boot image profiles
per-file boot-* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
per-file dirty-image-objects = calin@google.com, mathieuc@google.com, ngeoffray@google.com
per-file generate-preloaded-classes.sh = calin@google.com, mathieuc@google.com, ngeoffray@google.com
per-file preloaded-classes* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
-# Escalations:
-per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index 10c4a4f..88080f0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1182,7 +1182,7 @@
field public static final int reqNavigation = 16843306; // 0x101022a
field public static final int reqTouchScreen = 16843303; // 0x1010227
field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
- field public static final int requestOptimizedExternalStorageAccess;
+ field public static final int requestRawExternalStorageAccess;
field public static final int requireDeviceScreenOn;
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
@@ -8552,8 +8552,8 @@
ctor public AppWidgetProviderInfo(android.os.Parcel);
method public android.appwidget.AppWidgetProviderInfo clone();
method public int describeContents();
+ method @NonNull public android.content.pm.ActivityInfo getActivityInfo();
method public final android.os.UserHandle getProfile();
- method @NonNull public android.content.pm.ActivityInfo getProviderInfo();
method @Nullable public final CharSequence loadDescription(@NonNull android.content.Context);
method public final android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context, int);
method public final String loadLabel(android.content.pm.PackageManager);
@@ -12441,7 +12441,7 @@
method public void setAppIcon(@Nullable android.graphics.Bitmap);
method public void setAppLabel(@Nullable CharSequence);
method public void setAppPackageName(@Nullable String);
- method public void setAutoRevokePermissionsMode(boolean);
+ method @Deprecated public void setAutoRevokePermissionsMode(boolean);
method public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
method public void setInstallLocation(int);
method public void setInstallReason(int);
@@ -20332,6 +20332,7 @@
field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
+ field public static final int ENCODING_DTS_UHD = 27; // 0x1b
field public static final int ENCODING_E_AC3 = 6; // 0x6
field public static final int ENCODING_E_AC3_JOC = 18; // 0x12
field public static final int ENCODING_IEC61937 = 13; // 0xd
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c126dbd..0772478 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -69,6 +69,7 @@
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
+ field public static final String BYPASS_ROLE_QUALIFICATION = "android.permission.BYPASS_ROLE_QUALIFICATION";
field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
field public static final String CAMERA_OPEN_CLOSE_LISTENER = "android.permission.CAMERA_OPEN_CLOSE_LISTENER";
field public static final String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD";
@@ -2508,7 +2509,7 @@
package android.content.pm {
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- method @Nullable public Boolean hasRequestOptimizedExternalStorageAccess();
+ method @Nullable public Boolean hasRequestRawExternalStorageAccess();
method public boolean isEncryptionAware();
method public boolean isInstantApp();
method public boolean isOem();
@@ -9439,7 +9440,7 @@
}
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
- method @Nullable public int[] getAttestationIds();
+ method @NonNull public int[] getAttestationIds();
method public int getNamespace();
}
@@ -14240,7 +14241,7 @@
method public void onStartFailed(int, @NonNull android.os.PersistableBundle);
method public void onStarted(@NonNull android.os.PersistableBundle);
method public void onStopFailed(int, @NonNull android.os.PersistableBundle);
- method public void onStopped();
+ method public void onStopped(int, @NonNull android.os.PersistableBundle);
field public static final int REASON_BAD_PARAMETERS = 3; // 0x3
field public static final int REASON_GENERIC_ERROR = 4; // 0x4
field public static final int REASON_LOCAL_REQUEST = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9931bf9..906524e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -233,6 +233,8 @@
field public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time";
field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
+ field public static final String OPSTR_ACTIVITY_RECOGNITION = "android:activity_recognition";
+ field public static final String OPSTR_ACTIVITY_RECOGNITION_SOURCE = "android:activity_recognition_source";
field public static final String OPSTR_MANAGE_ONGOING_CALLS = "android:manage_ongoing_calls";
field public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
field public static final String OPSTR_PHONE_CALL_MICROPHONE = "android:phone_call_microphone";
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e50432e..35890c8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4335,17 +4335,10 @@
private String getBackupAgentName(CreateBackupAgentData data) {
String agentName = data.appInfo.backupAgentName;
- if (!UserHandle.isCore(data.appInfo.uid)
- && data.operationType == BackupManager.OperationType.MIGRATION) {
- // If this is a migration, use the default backup agent regardless of the app's
- // preferences.
+ // full backup operation but no app-supplied agent? use the default implementation
+ if (agentName == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL
+ || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) {
agentName = DEFAULT_FULL_BACKUP_AGENT;
- } else {
- // full backup operation but no app-supplied agent? use the default implementation
- if (agentName == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL
- || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) {
- agentName = DEFAULT_FULL_BACKUP_AGENT;
- }
}
return agentName;
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 436007ca..8e2626a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1225,9 +1225,19 @@
/** @hide */
public static final int OP_UWB_RANGING = AppProtoEnums.APP_OP_UWB_RANGING;
+ /**
+ * Activity recognition being accessed by an activity recognition source, which
+ * is a component that already has access since it is the one that detects
+ * activity recognition.
+ *
+ * @hide
+ */
+ public static final int OP_ACTIVITY_RECOGNITION_SOURCE =
+ AppProtoEnums.APP_OP_ACTIVITY_RECOGNITION_SOURCE;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 113;
+ public static final int _NUM_OP = 114;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1478,6 +1488,7 @@
public static final String OPSTR_USE_BIOMETRIC = "android:use_biometric";
/** @hide Recognize physical activity. */
+ @TestApi
public static final String OPSTR_ACTIVITY_RECOGNITION = "android:activity_recognition";
/** @hide Financial app read sms. */
@@ -1643,6 +1654,17 @@
/** @hide */
public static final String OPSTR_UWB_RANGING = "android:uwb_ranging";
+ /**
+ * Activity recognition being accessed by an activity recognition source, which
+ * is a component that already has access since it is the one that detects
+ * activity recognition.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String OPSTR_ACTIVITY_RECOGNITION_SOURCE =
+ "android:activity_recognition_source";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1853,6 +1875,7 @@
OP_MANAGE_MEDIA, // MANAGE_MEDIA
OP_BLUETOOTH_CONNECT, // OP_BLUETOOTH_CONNECT
OP_UWB_RANGING, // OP_UWB_RANGING
+ OP_ACTIVITY_RECOGNITION_SOURCE // OP_ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -1972,6 +1995,7 @@
OPSTR_MANAGE_MEDIA,
OPSTR_BLUETOOTH_CONNECT,
OPSTR_UWB_RANGING,
+ OPSTR_ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2091,7 +2115,8 @@
"COARSE_LOCATION_SOURCE",
"MANAGE_MEDIA",
"BLUETOOTH_CONNECT",
- "UWB_RANGING"
+ "UWB_RANGING",
+ "ACTIVITY_RECOGNITION_SOURCE"
};
/**
@@ -2213,6 +2238,7 @@
Manifest.permission.MANAGE_MEDIA,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.UWB_RANGING,
+ null, // no permission for OP_ACTIVITY_RECOGNITION_SOURCE,
};
/**
@@ -2334,6 +2360,7 @@
null, // MANAGE_MEDIA
null, // BLUETOOTH_CONNECT
null, // UWB_RANGING
+ null, // ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2454,6 +2481,7 @@
null, // MANAGE_MEDIA
null, // BLUETOOTH_CONNECT
null, // UWB_RANGING
+ null // ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2573,6 +2601,7 @@
AppOpsManager.MODE_DEFAULT, // MANAGE_MEDIA
AppOpsManager.MODE_ALLOWED, // BLUETOOTH_CONNECT
AppOpsManager.MODE_ALLOWED, // UWB_RANGING
+ AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2696,6 +2725,7 @@
false, // MANAGE_MEDIA
false, // BLUETOOTH_CONNECT
false, // UWB_RANGING
+ false, // ACTIVITY_RECOGNITION_SOURCE
};
/**
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index 7713e25..74018a8 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -24,7 +24,7 @@
// below block of transactions.
// Since these transactions are also called from native code, these must be kept in sync with
- // the ones in frameworks/native/include/binder/IActivityManager.h
+ // the ones in frameworks/native/include_activitymanager/binder/IActivityManager.h
// =============== Beginning of transactions used on native side as well ======================
/**
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index f0d580f..da03a3d 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -419,6 +419,14 @@
@Retention(RetentionPolicy.SOURCE)
public @interface Importance {}
+ /** @hide */
+ @IntDef(prefix = { "BUBBLE_PREFERENCE_" }, value = {
+ BUBBLE_PREFERENCE_NONE, BUBBLE_PREFERENCE_SELECTED,
+ BUBBLE_PREFERENCE_ALL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BubblePreference {}
+
/**
* Activity Action: Launch an Automatic Zen Rule configuration screen
* <p>
@@ -1379,7 +1387,7 @@
* @see Notification#getBubbleMetadata()
* @return the users' bubble preference for the app.
*/
- public int getBubblePreference() {
+ public @BubblePreference int getBubblePreference() {
INotificationManager service = getService();
try {
return service.getBubblePreferenceForPackage(mContext.getPackageName(),
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 94a4fde0..0841910 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -544,11 +544,6 @@
}
private Set<String> getExtraExcludeDirsIfAny(Context context) throws IOException {
- if (isDeviceToDeviceMigration()) {
- return Collections.emptySet();
- }
-
- // If this is not a migration, also exclude no-backup and cache dirs.
Set<String> excludedDirs = new HashSet<>();
excludedDirs.add(context.getCacheDir().getCanonicalPath());
excludedDirs.add(context.getCodeCacheDir().getCanonicalPath());
@@ -556,10 +551,6 @@
return Collections.unmodifiableSet(excludedDirs);
}
- private boolean isDeviceToDeviceMigration() {
- return mOperationType == OperationType.MIGRATION;
- }
-
/** @hide */
@VisibleForTesting
public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme)
@@ -905,11 +896,6 @@
}
private boolean isFileEligibleForRestore(File destination) throws IOException {
- if (isDeviceToDeviceMigration()) {
- // Everything is eligible for device-to-device migration.
- return true;
- }
-
FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this, mOperationType);
if (!bs.isFullRestoreEnabled()) {
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java
index 066aada..f506f12 100644
--- a/core/java/android/app/time/LocationTimeZoneManager.java
+++ b/core/java/android/app/time/LocationTimeZoneManager.java
@@ -50,31 +50,6 @@
public static final String SHELL_COMMAND_STOP = "stop";
/**
- * A shell command that can put providers into different modes. Takes effect next time the
- * service is started.
- */
- public static final String SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE =
- "set_provider_mode_override";
-
- /**
- * The default provider mode.
- * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
- */
- public static final String PROVIDER_MODE_OVERRIDE_NONE = "none";
-
- /**
- * The "simulated" provider mode.
- * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
- */
- public static final String PROVIDER_MODE_OVERRIDE_SIMULATED = "simulated";
-
- /**
- * The "disabled" provider mode (equivalent to there being no provider configured).
- * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
- */
- public static final String PROVIDER_MODE_OVERRIDE_DISABLED = "disabled";
-
- /**
* A shell command that tells the service to record state information during tests. The next
* argument value is "true" or "false".
*/
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 1cbb2fb..3db1885 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -479,7 +479,7 @@
* Returns the broadcast receiver that is providing this widget.
*/
@NonNull
- public ActivityInfo getProviderInfo() {
+ public ActivityInfo getActivityInfo() {
return providerInfo;
}
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index b07d6d5..7956be3 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -67,6 +67,9 @@
* Using it requires declaring uses-permission
* {@link android.Manifest.permission#REQUEST_COMPANION_PROFILE_WATCH} in the manifest.
*
+ * <a href="{@docRoot}about/versions/12/features#cdm-profiles">Learn more</a>
+ * about device profiles.
+ *
* @see AssociationRequest.Builder#setDeviceProfile
*/
public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 2ce7156..0116db0 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -375,6 +375,14 @@
* Calling app must check for feature presence of
* {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} before calling this API.
*
+ * For Bluetooth LE devices this is based on scanning for device with the given address.
+ * For Bluetooth classic devices this is triggered when the device connects/disconnects.
+ * WiFi devices are not supported.
+ *
+ * If a Bluetooth LE device wants to use a rotating mac address, it is recommended to use
+ * Resolvable Private Address, and ensure the device is bonded to the phone so that android OS
+ * is able to resolve the address.
+ *
* @param deviceAddress a previously-associated companion device's address
*
* @throws DeviceNotAssociatedException if the given device was not previously associated
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index cadbd60..11adfa3 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -51,6 +51,25 @@
*/
@SystemService(Context.CLIPBOARD_SERVICE)
public class ClipboardManager extends android.text.ClipboardManager {
+
+ /**
+ * DeviceConfig property, within the clipboard namespace, that determines whether notifications
+ * are shown when an app accesses clipboard. This may be overridden by a user-controlled
+ * setting.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_SHOW_ACCESS_NOTIFICATIONS =
+ "show_access_notifications";
+
+ /**
+ * Default value for the DeviceConfig property that determines whether notifications are shown
+ * when an app accesses clipboard.
+ *
+ * @hide
+ */
+ public static final boolean DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS = true;
+
private final Context mContext;
private final Handler mHandler;
private final IClipboard mService;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6badf0e0..6ad204e 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1436,11 +1436,11 @@
private @NativeHeapZeroInitialized int nativeHeapZeroInitialized = ZEROINIT_DEFAULT;
/**
- * If {@code true} this app requests optimized external storage access.
+ * If {@code true} this app requests raw external storage access.
* The request may not be honored due to policy or other reasons.
*/
@Nullable
- private Boolean requestOptimizedExternalStorageAccess;
+ private Boolean requestRawExternalStorageAccess;
/**
* Represents the default policy. The actual policy used will depend on other properties of
@@ -1598,9 +1598,9 @@
if (nativeHeapZeroInitialized != ZEROINIT_DEFAULT) {
pw.println(prefix + "nativeHeapZeroInitialized=" + nativeHeapZeroInitialized);
}
- if (requestOptimizedExternalStorageAccess != null) {
- pw.println(prefix + "requestOptimizedExternalStorageAccess="
- + requestOptimizedExternalStorageAccess);
+ if (requestRawExternalStorageAccess != null) {
+ pw.println(prefix + "requestRawExternalStorageAccess="
+ + requestRawExternalStorageAccess);
}
}
super.dumpBack(pw, prefix);
@@ -1829,7 +1829,7 @@
gwpAsanMode = orig.gwpAsanMode;
memtagMode = orig.memtagMode;
nativeHeapZeroInitialized = orig.nativeHeapZeroInitialized;
- requestOptimizedExternalStorageAccess = orig.requestOptimizedExternalStorageAccess;
+ requestRawExternalStorageAccess = orig.requestRawExternalStorageAccess;
}
public String toString() {
@@ -1918,7 +1918,7 @@
dest.writeInt(gwpAsanMode);
dest.writeInt(memtagMode);
dest.writeInt(nativeHeapZeroInitialized);
- sForBoolean.parcel(requestOptimizedExternalStorageAccess, dest, parcelableFlags);
+ sForBoolean.parcel(requestRawExternalStorageAccess, dest, parcelableFlags);
}
public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR
@@ -2004,7 +2004,7 @@
gwpAsanMode = source.readInt();
memtagMode = source.readInt();
nativeHeapZeroInitialized = source.readInt();
- requestOptimizedExternalStorageAccess = sForBoolean.unparcel(source);
+ requestRawExternalStorageAccess = sForBoolean.unparcel(source);
}
/**
@@ -2121,10 +2121,10 @@
/**
* @return
* <ul>
- * <li>{@code true} if this app requested optimized external storage access
- * <li>{@code false} if this app requests to disable optimized external storage access.
+ * <li>{@code true} if this app requested raw external storage access
+ * <li>{@code false} if this app requests to disable raw external storage access.
* <li>{@code null} if the app didn't specify
- * {@link android.R.styleable#AndroidManifestApplication_requestOptimizedExternalStorageAccess}
+ * {@link android.R.styleable#AndroidManifestApplication_requestRawExternalStorageAccess}
* in its manifest file.
* </ul>
*
@@ -2132,8 +2132,8 @@
*/
@SystemApi
@Nullable
- public Boolean hasRequestOptimizedExternalStorageAccess() {
- return requestOptimizedExternalStorageAccess;
+ public Boolean hasRequestRawExternalStorageAccess() {
+ return requestRawExternalStorageAccess;
}
/**
@@ -2421,8 +2421,8 @@
nativeHeapZeroInitialized = value;
}
/** {@hide} */
- public void setRequestOptimizedExternalStorageAccess(@Nullable Boolean value) {
- requestOptimizedExternalStorageAccess = value;
+ public void setRequestRawExternalStorageAccess(@Nullable Boolean value) {
+ requestRawExternalStorageAccess = value;
}
/** {@hide} */
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3be7f74..0be77e0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1808,7 +1808,10 @@
* If user explicitly enabled or disabled it via settings, this call is ignored.
*
* @param shouldAutoRevoke whether permissions should be auto-revoked.
+ *
+ * @deprecated No longer used
*/
+ @Deprecated
public void setAutoRevokePermissionsMode(boolean shouldAutoRevoke) {
autoRevokePermissionsMode = shouldAutoRevoke ? MODE_ALLOWED : MODE_IGNORED;
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 1c65e00..8dcba7f 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -259,8 +259,8 @@
ParsingPackage setNativeHeapZeroInitialized(
@ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized);
- ParsingPackage setRequestOptimizedExternalStorageAccess(
- @Nullable Boolean requestOptimizedExternalStorageAccess);
+ ParsingPackage setRequestRawExternalStorageAccess(
+ @Nullable Boolean requestRawExternalStorageAccess);
ParsingPackage setCrossProfile(boolean crossProfile);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 97e1b54..ea7135e 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -400,7 +400,7 @@
@Nullable
@DataClass.ParcelWith(ForBoolean.class)
- private Boolean requestOptimizedExternalStorageAccess;
+ private Boolean requestRawExternalStorageAccess;
// TODO(chiuwinson): Non-null
@Nullable
@@ -1086,7 +1086,7 @@
appInfo.setGwpAsanMode(gwpAsanMode);
appInfo.setMemtagMode(memtagMode);
appInfo.setNativeHeapZeroInitialized(nativeHeapZeroInitialized);
- appInfo.setRequestOptimizedExternalStorageAccess(requestOptimizedExternalStorageAccess);
+ appInfo.setRequestRawExternalStorageAccess(requestRawExternalStorageAccess);
appInfo.setBaseCodePath(mBaseApkPath);
appInfo.setBaseResourcePath(mBaseApkPath);
appInfo.setCodePath(mPath);
@@ -1223,7 +1223,7 @@
dest.writeMap(this.mProperties);
dest.writeInt(this.memtagMode);
dest.writeInt(this.nativeHeapZeroInitialized);
- sForBoolean.parcel(this.requestOptimizedExternalStorageAccess, dest, flags);
+ sForBoolean.parcel(this.requestRawExternalStorageAccess, dest, flags);
}
public ParsingPackageImpl(Parcel in) {
@@ -1348,7 +1348,7 @@
this.mProperties = in.readHashMap(boot);
this.memtagMode = in.readInt();
this.nativeHeapZeroInitialized = in.readInt();
- this.requestOptimizedExternalStorageAccess = sForBoolean.unparcel(in);
+ this.requestRawExternalStorageAccess = sForBoolean.unparcel(in);
assignDerivedFields();
}
@@ -2131,8 +2131,8 @@
@Nullable
@Override
- public Boolean hasRequestOptimizedExternalStorageAccess() {
- return requestOptimizedExternalStorageAccess;
+ public Boolean hasRequestRawExternalStorageAccess() {
+ return requestRawExternalStorageAccess;
}
@Override
@@ -2586,8 +2586,8 @@
}
@Override
- public ParsingPackageImpl setRequestOptimizedExternalStorageAccess(@Nullable Boolean value) {
- requestOptimizedExternalStorageAccess = value;
+ public ParsingPackageImpl setRequestRawExternalStorageAccess(@Nullable Boolean value) {
+ requestRawExternalStorageAccess = value;
return this;
}
@Override
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index cfd828e..4d4cc1a 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -905,7 +905,7 @@
int getNativeHeapZeroInitialized();
@Nullable
- Boolean hasRequestOptimizedExternalStorageAccess();
+ Boolean hasRequestRawExternalStorageAccess();
// TODO(b/135203078): Hide and enforce going through PackageInfoUtils
ApplicationInfo toAppInfoWithoutState();
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 4e7bd70..a1ffc0c 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2019,9 +2019,9 @@
v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED);
}
if (sa.hasValue(
- R.styleable.AndroidManifestApplication_requestOptimizedExternalStorageAccess)) {
- pkg.setRequestOptimizedExternalStorageAccess(sa.getBoolean(R.styleable
- .AndroidManifestApplication_requestOptimizedExternalStorageAccess,
+ R.styleable.AndroidManifestApplication_requestRawExternalStorageAccess)) {
+ pkg.setRequestRawExternalStorageAccess(sa.getBoolean(R.styleable
+ .AndroidManifestApplication_requestRawExternalStorageAccess,
false));
}
} finally {
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index d7bb226..ba6fc6e 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -53,6 +53,11 @@
in PerUidReadTimeouts[] perUidReadTimeouts);
/**
+ * PM/system is done with this storage, ok to increase timeouts.
+ */
+ void onInstallationComplete(int storageId);
+
+ /**
* Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
*/
const int BIND_TEMPORARY = 0;
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 2a42b98..6e25968 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -205,16 +205,26 @@
/**
* Resets the states and unbinds storage instances for an installation session.
*/
- public void cleanUp() {
- if (mDefaultStorage == null) {
- return;
+ public void cleanUpAndMarkComplete() {
+ IncrementalStorage defaultStorage = cleanUp();
+ if (defaultStorage != null) {
+ defaultStorage.onInstallationComplete();
+ }
+ }
+
+ private IncrementalStorage cleanUp() {
+ IncrementalStorage defaultStorage = mDefaultStorage;
+ mInheritedStorage = null;
+ mDefaultStorage = null;
+ if (defaultStorage == null) {
+ return null;
}
try {
mIncrementalManager.unregisterLoadingProgressCallbacks(mStageDir.getAbsolutePath());
- mDefaultStorage.unBind(mStageDir.getAbsolutePath());
+ defaultStorage.unBind(mStageDir.getAbsolutePath());
} catch (IOException ignored) {
}
- mDefaultStorage = null;
+ return defaultStorage;
}
}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 7cf0144..c19e29f 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -398,7 +398,7 @@
}
/**
- * Iinitializes and starts the DataLoader.
+ * Initializes and starts the DataLoader.
* This makes sure all install-time parameters are applied.
* Does not affect persistent DataLoader params.
* @return True if start request was successfully queued.
@@ -419,6 +419,18 @@
}
}
+ /**
+ * Marks the completion of installation.
+ */
+ public void onInstallationComplete() {
+ try {
+ mService.onInstallationComplete(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+
private static final int UUID_BYTE_SIZE = 16;
/**
diff --git a/core/java/android/uwb/IUwbRangingCallbacks.aidl b/core/java/android/uwb/IUwbRangingCallbacks.aidl
index f71f3ff..f15debb 100644
--- a/core/java/android/uwb/IUwbRangingCallbacks.aidl
+++ b/core/java/android/uwb/IUwbRangingCallbacks.aidl
@@ -92,9 +92,13 @@
* Called when the ranging session has been stopped
*
* @param sessionHandle the session the callback is being invoked for
+ * @param reason the reason the session was stopped
+ * @param parameters protocol specific parameters
*/
- void onRangingStopped(in SessionHandle sessionHandle);
+ void onRangingStopped(in SessionHandle sessionHandle,
+ RangingChangeReason reason,
+ in PersistableBundle parameters);
/**
* Called when a ranging session fails to stop
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
index 5c7f0f5..ff8b912 100644
--- a/core/java/android/uwb/RangingManager.java
+++ b/core/java/android/uwb/RangingManager.java
@@ -171,7 +171,8 @@
}
@Override
- public void onRangingStopped(SessionHandle sessionHandle) {
+ public void onRangingStopped(SessionHandle sessionHandle, @RangingChangeReason int reason,
+ PersistableBundle params) {
synchronized (this) {
if (!hasSession(sessionHandle)) {
Log.w(TAG, "onRangingStopped - received unexpected SessionHandle: "
@@ -180,7 +181,7 @@
}
RangingSession session = mRangingSessionTable.get(sessionHandle);
- session.onRangingStopped();
+ session.onRangingStopped(convertToReason(reason), params);
}
}
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index 52ec5bd..345b69d 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -191,8 +191,11 @@
/**
* Invoked when a request to stop the session succeeds
+ *
+ * @param reason reason for the session stop
+ * @param parameters protocol specific parameters related to the stop reason
*/
- void onStopped();
+ void onStopped(@Reason int reason, @NonNull PersistableBundle parameters);
/**
* Invoked when a request to stop the session fails
@@ -434,14 +437,15 @@
/**
* @hide
*/
- public void onRangingStopped() {
+ public void onRangingStopped(@Callback.Reason int reason,
+ @NonNull PersistableBundle params) {
if (mState == State.CLOSED) {
Log.w(TAG, "onRangingStopped invoked for a closed session");
return;
}
mState = State.IDLE;
- executeCallback(() -> mCallback.onStopped());
+ executeCallback(() -> mCallback.onStopped(reason, params));
}
/**
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index b207ad3..04528e9 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -16,6 +16,8 @@
#define ATRACE_TAG ATRACE_TAG_RESOURCES
+#include "signal.h"
+
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
@@ -353,8 +355,59 @@
return reinterpret_cast<jlong>(apk_assets.release());
}
+// STOPSHIP (b/159041693): Revert signal handler when reason for issue is found.
+static thread_local std::stringstream destroy_info;
+static struct sigaction old_handler_action;
+
+static void DestroyErrorHandler(int sig, siginfo_t* info, void* ucontext) {
+ if (sig != SIGSEGV) {
+ return;
+ }
+
+ LOG(ERROR) << "(b/159041693) - Failed to destroy ApkAssets " << destroy_info.str();
+ if (old_handler_action.sa_handler == SIG_DFL) {
+ // reset the action to default and re-raise the signal. It will kill the process
+ signal(sig, SIG_DFL);
+ raise(sig);
+ return;
+ }
+ if (old_handler_action.sa_handler == SIG_IGN) {
+ // ignoring SIGBUS won't help us much, as we'll get back right here after retrying.
+ return;
+ }
+ if (old_handler_action.sa_flags & SA_SIGINFO) {
+ old_handler_action.sa_sigaction(sig, info, ucontext);
+ } else {
+ old_handler_action.sa_handler(sig);
+ }
+}
+
static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
- delete reinterpret_cast<ApkAssets*>(ptr);
+ auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+ destroy_info << "{ptr=" << apk_assets;
+ if (apk_assets != nullptr) {
+ destroy_info << ", name='" << apk_assets->GetDebugName() << "'"
+ << ", idmap=" << apk_assets->GetLoadedIdmap()
+ << ", {arsc=" << apk_assets->GetLoadedArsc();
+ if (auto arsc = apk_assets->GetLoadedArsc()) {
+ destroy_info << ", strings=" << arsc->GetStringPool()
+ << ", packages=" << &arsc->GetPackages()
+ << " [";
+ for (auto& package : arsc->GetPackages()) {
+ destroy_info << "{unique_ptr=" << &package
+ << ", package=" << package.get() << "},";
+ }
+ destroy_info << "]";
+ }
+ destroy_info << "}";
+ }
+ destroy_info << "}";
+
+ delete apk_assets;
+
+ // Deleting the apk assets did not lead to a crash.
+ destroy_info.str("");
+ destroy_info.clear();
}
static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
@@ -507,6 +560,17 @@
jclass parcelFd = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
gParcelFileDescriptorOffsets.detachFd = GetMethodIDOrDie(env, parcelFd, "detachFd", "()I");
+ // STOPSHIP (b/159041693): Revert signal handler when reason for issue is found.
+ sigset_t allowed;
+ sigemptyset(&allowed);
+ sigaddset(&allowed, SIGSEGV);
+ pthread_sigmask(SIG_UNBLOCK, &allowed, nullptr);
+ struct sigaction action = {
+ .sa_flags = SA_SIGINFO,
+ .sa_sigaction = &DestroyErrorHandler,
+ };
+ sigaction(SIGSEGV, &action, &old_handler_action);
+
return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
arraysize(gApkAssetsMethods));
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 5630a1e..7fde92c 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -45,6 +45,7 @@
#define ENCODING_MPEGH_BL_L4 24
#define ENCODING_MPEGH_LC_L3 25
#define ENCODING_MPEGH_LC_L4 26
+#define ENCODING_DTS_UHD 27
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -110,6 +111,8 @@
return AUDIO_FORMAT_MPEGH_LC_L3;
case ENCODING_MPEGH_LC_L4:
return AUDIO_FORMAT_MPEGH_LC_L4;
+ case ENCODING_DTS_UHD:
+ return AUDIO_FORMAT_DTS_UHD;
default:
return AUDIO_FORMAT_INVALID;
}
@@ -179,6 +182,8 @@
return ENCODING_MPEGH_LC_L3;
case AUDIO_FORMAT_MPEGH_LC_L4:
return ENCODING_MPEGH_LC_L4;
+ case AUDIO_FORMAT_DTS_UHD:
+ return ENCODING_DTS_UHD;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f5cc24d..58abfeb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1390,7 +1390,7 @@
<!-- Required to be able to discover and connect to nearby Bluetooth devices.
<p>Protection level: dangerous -->
<permission-group android:name="android.permission-group.NEARBY_DEVICES"
- android:icon="@drawable/ic_qs_bluetooth"
+ android:icon="@drawable/perm_group_nearby_devices"
android:label="@string/permgrouplab_nearby_devices"
android:description="@string/permgroupdesc_nearby_devices"
android:priority="750" />
@@ -4240,6 +4240,15 @@
<permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
android:protectionLevel="signature|installer" />
+ <!-- @SystemApi Allows an application to bypass role qualification. This allows switching role
+ holders to otherwise non eligible holders. Only the shell is allowed to do this, the
+ qualification for the shell role itself cannot be bypassed, and each role needs to
+ explicitly allow bypassing qualification in its definition. The bypass state will not be
+ persisted across reboot.
+ @hide -->
+ <permission android:name="android.permission.BYPASS_ROLE_QUALIFICATION"
+ android:protectionLevel="internal|role" />
+
<!-- @SystemApi Allows an application to observe role holder changes.
@hide -->
<permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"
diff --git a/core/res/res/drawable/perm_group_nearby_devices.xml b/core/res/res/drawable/perm_group_nearby_devices.xml
new file mode 100644
index 0000000..84cc432
--- /dev/null
+++ b/core/res/res/drawable/perm_group_nearby_devices.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M12,16.427L7.574,12 12,7.574 16.426,12zM10.58,2.59l-8,8c-0.78,0.78 -0.78,2.05 0,2.83l8,8c0.78,0.78 2.05,0.78 2.83,0l8,-8c0.78,-0.78 0.78,-2.05 0,-2.83l-8,-8c-0.78,-0.79 -2.04,-0.79 -2.83,0zM13.39,17.81L12,19.2l-1.39,-1.39 -4.42,-4.42L4.8,12l1.39,-1.39 4.42,-4.42L12,4.8l1.39,1.39 4.42,4.42L19.2,12l-1.39,1.39 -4.42,4.42z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 986bb82..c51b2d8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1867,16 +1867,21 @@
-->
<attr name="preserveLegacyExternalStorage" format="boolean" />
- <!-- If {@code true} this app would like optimized external storage access.
+ <!-- If {@code true} this app would like raw external storage access.
<p> This flag can only be used by apps holding
<ul>
<li>{@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission or
<li>{@link android.app.role}#SYSTEM_GALLERY role.
</ul>
- When the flag is set, bulk file path operations will be optimized.
+ <p> When the flag is set, all file path access on external storage will bypass database
+ operations that update MediaStore collection. Raw external storage access as a side effect
+ can improve performance of bulk file path operations but can cause unexpected behavior in
+ apps due to inconsistencies in MediaStore collection and lower file system.
+ When the flag is set, app should scan the file after file path operations to ensure
+ consistency of MediaStore collection.
- The default value is {@code true} if
+ <p> The default value is {@code true} if
<ul>
<li>app has {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission and
targets targetSDK<=30.
@@ -1884,7 +1889,7 @@
</ul>
{@code false} otherwise.
-->
- <attr name="requestOptimizedExternalStorageAccess" format="boolean" />
+ <attr name="requestRawExternalStorageAccess" format="boolean" />
<!-- If {@code true} this app declares that it should be visible to all other apps on
device, regardless of what they declare via the {@code queries} tags in their
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 0b41769..cb7f69b 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -34,7 +34,7 @@
<color name="quaternary_device_default_settings">@color/quaternary_material_settings</color>
<color name="accent_device_default_light">@color/system_accent1_600</color>
- <color name="accent_device_default_dark">@color/system_accent1_200</color>
+ <color name="accent_device_default_dark">@color/system_accent1_100</color>
<color name="accent_device_default">@color/accent_device_default_light</color>
<color name="accent_primary_device_default">@color/system_accent1_100</color>
<color name="accent_secondary_device_default">@color/system_accent2_100</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fc2bdf3..49bd853 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1637,32 +1637,22 @@
config_timeZoneRulesUpdateTrackingEnabled are true.] -->
<integer name="config_timeZoneRulesCheckRetryCount">5</integer>
- <!-- Whether the geolocation time zone detection feature is enabled. -->
+ <!-- Whether the geolocation time zone detection feature is enabled. Setting this to false means
+ the feature cannot be used. Setting this to true means it may be used if other
+ configuration allows (see provider configuration below, also compile time overlays). -->
<bool name="config_enableGeolocationTimeZoneDetection" translatable="false">true</bool>
- <!-- Whether the primary LocationTimeZoneProvider is enabled device.
+ <!-- Whether the primary LocationTimeZoneProvider is enabled.
Ignored if config_enableGeolocationTimeZoneDetection is false -->
<bool name="config_enablePrimaryLocationTimeZoneProvider" translatable="false">false</bool>
- <!-- Used when enablePrimaryLocationTimeZoneProvider is true. Controls whether to enable primary
- location time zone provider overlay which allows the primary location time zone provider to
- be replaced by an app at run-time. When disabled, only the
- config_primaryLocationTimeZoneProviderPackageName package will be searched for the primary
- location time zone provider, otherwise any system package is eligible. Anyone who wants to
- disable the runtime overlay mechanism can set it to false. -->
- <bool name="config_enablePrimaryLocationTimeZoneOverlay" translatable="false">false</bool>
- <!-- Package name providing the primary location time zone provider. Used only when
- config_enablePrimaryLocationTimeZoneOverlay is false. -->
+ <!-- The package name providing the primary location time zone provider.
+ Only used when config_enableGeolocationTimeZoneDetection and
+ enablePrimaryLocationTimeZoneProvider are true. -->
<string name="config_primaryLocationTimeZoneProviderPackageName" translatable="false">@null</string>
- <!-- Whether the secondary LocationTimeZoneProvider is enabled device.
+ <!-- Whether the secondary LocationTimeZoneProvider is enabled.
Ignored if config_enableGeolocationTimeZoneDetection is false -->
<bool name="config_enableSecondaryLocationTimeZoneProvider" translatable="false">true</bool>
- <!-- Used when enableSecondaryLocationTimeZoneProvider is true. Controls whether to enable
- secondary location time zone provider overlay which allows the primary location time zone
- provider to config_secondaryLocationTimeZoneProviderPackageName package will be searched
- for the secondary location time zone provider, otherwise any system package is eligible.
- Anyone who wants to disable the runtime overlay mechanism can set it to false. -->
- <bool name="config_enableSecondaryLocationTimeZoneOverlay" translatable="false">false</bool>
<!-- Package name providing the secondary location time zone provider. Used only when
config_enableSecondaryLocationTimeZoneOverlay is false.
@@ -1942,11 +1932,13 @@
<!-- The name of the package that will hold the speech recognizer role by default. -->
<string name="config_systemSpeechRecognizer" translatable="false"></string>
<!-- The name of the package that will hold the system Wi-Fi coex manager role. -->
- <string name="config_systemWifiCoexManager" translateable="false"></string>
+ <string name="config_systemWifiCoexManager" translatable="false"></string>
<!-- The name of the package that will hold the wellbeing role. -->
<string name="config_systemWellbeing" translatable="false"></string>
<!-- The name of the package that will hold the television notification handler role -->
<string name="config_systemTelevisionNotificationHandler" translatable="false"></string>
+ <!-- The name of the package that will hold the system activity recognizer role. -->
+ <string name="config_systemActivityRecognizer" translatable="false"></string>
<!-- The name of the package that will be allowed to change its components' label/icon. -->
<string name="config_overrideComponentUiPackage" translatable="false"></string>
@@ -2580,10 +2572,6 @@
<!-- Set to true if after a provisioning apn the radio should be restarted -->
<bool name="config_restartRadioAfterProvisioning">false</bool>
- <!-- Boolean indicating if RADIO POWER OFF is required on receiving SIM REFRESH with RESET.
- This will be handled by modem if it is false. -->
- <bool name="config_requireRadioPowerOffOnSimRefreshReset">false</bool>
-
<!-- Vibrator pattern to be used as the default for notifications
that specify DEFAULT_VIBRATE.
-->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b402c95..3a5621b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3092,7 +3092,7 @@
<public name="attributionTags"/>
<public name="suppressesSpellChecker" />
<public name="usesPermissionFlags" />
- <public name="requestOptimizedExternalStorageAccess" />
+ <public name="requestRawExternalStorageAccess" />
<!-- @hide @SystemApi -->
<public name="playHomeTransitionSound" />
<public name="lStar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4c421ed..90e9c09 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -823,9 +823,9 @@
<string name="permgroupdesc_camera">take pictures and record video</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
- <string name="permgrouplab_nearby_devices">Nearby Bluetooth Devices</string>
+ <string name="permgrouplab_nearby_devices">Nearby devices</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
- <string name="permgroupdesc_nearby_devices">discover and connect to nearby Bluetooth devices</string>
+ <string name="permgroupdesc_nearby_devices">discover and connect to nearby devices</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_calllog">Call logs</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eb1fe1d..dbfb030 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -350,7 +350,6 @@
<java-symbol type="bool" name="config_camera_sound_forced" />
<java-symbol type="bool" name="config_dontPreferApn" />
<java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
- <java-symbol type="bool" name="config_requireRadioPowerOffOnSimRefreshReset" />
<java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
<java-symbol type="bool" name="config_useFixedVolume" />
<java-symbol type="bool" name="config_enableMultiUserUI"/>
@@ -2180,10 +2179,8 @@
<java-symbol type="bool" name="config_enableGnssTimeUpdateService" />
<java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" />
<java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneProvider" />
- <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
<java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
- <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
<java-symbol type="layout" name="resolver_list" />
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index dd60dd4..1a63660 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -44,8 +44,6 @@
import com.android.bandwidthtest.NetworkState.StateTransitionDirection;
import com.android.internal.util.AsyncChannel;
-import junit.framework.Assert;
-
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.List;
@@ -76,7 +74,11 @@
private WifiManager mWifiManager;
private Context mContext;
// Verify connectivity state
- private static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
+ // ConnectivityManager.TYPE_* is deprecated and no longer extended, so use the max public
+ // network type - TYPE_VPN should be enough.
+ // TODO: Replace registering CONNECTIVITY_ACTION with registering NetworkCallback and check
+ // network by NetworkCapabilities.TRANSPORT_* and NetworkCapabilities.hasTransport() instead.
+ private static final int NUM_NETWORK_TYPES = ConnectivityManager.TYPE_VPN + 1;
private NetworkState[] mConnectivityState = new NetworkState[NUM_NETWORK_TYPES];
public ConnectionUtil(Context context) {
diff --git a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
index 8271bed..5de6d42 100644
--- a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
+++ b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
@@ -128,8 +128,8 @@
rangingManager.onRangingReconfigureFailed(handle, REASON, PARAMS);
verify(callback, times(1)).onReconfigureFailed(eq(REASON), eq(PARAMS));
- rangingManager.onRangingStopped(handle);
- verify(callback, times(1)).onStopped();
+ rangingManager.onRangingStopped(handle, REASON, PARAMS);
+ verify(callback, times(1)).onStopped(eq(REASON), eq(PARAMS));
rangingManager.onRangingStopFailed(handle, REASON, PARAMS);
verify(callback, times(1)).onStopFailed(eq(REASON), eq(PARAMS));
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0987f77..489da16 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -429,6 +429,7 @@
<permission name="android.permission.LOG_COMPAT_CHANGE" />
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<permission name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" />
+ <permission name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD" />
<!-- Permissions required to test ambient display. -->
<permission name="android.permission.READ_DREAM_STATE" />
<permission name="android.permission.WRITE_DREAM_STATE" />
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 9ee1ef1..c317831 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -89,7 +89,7 @@
}
public boolean shouldAnimateSparkle() {
- return mAnimateSparkle;
+ return mAnimateSparkle && ValueAnimator.getDurationScale() > 0;
}
public float getSparklePhase() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 8b8cbbc..0865332 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -180,6 +180,7 @@
private Matrix mMaskMatrix;
private PorterDuffColorFilter mMaskColorFilter;
private boolean mHasValidMask;
+ private int mComputedRadius = -1;
/** The current ripple. May be actively animating or pending entry. */
private RippleForeground mRipple;
@@ -385,9 +386,7 @@
mRipple.onBoundsChange();
}
- mState.mMaxRadius = mState.mMaxRadius <= 0 && mState.mRippleStyle != STYLE_SOLID
- ? (int) computeRadius()
- : mState.mMaxRadius;
+ mComputedRadius = Math.round(computeRadius());
invalidateSelf();
}
@@ -918,7 +917,7 @@
ColorFilter origFilter = p.getColorFilter();
p.setColorFilter(mMaskColorFilter);
p.setAlpha(alpha);
- c.drawCircle(cx, cy, mState.mMaxRadius, p);
+ c.drawCircle(cx, cy, getComputedRadius(), p);
p.setAlpha(origAlpha);
p.setColorFilter(origFilter);
}
@@ -930,11 +929,17 @@
return radius;
}
+ private int getComputedRadius() {
+ if (mState.mMaxRadius >= 0) return mState.mMaxRadius;
+ if (mComputedRadius >= 0) return mComputedRadius;
+ return (int) computeRadius();
+ }
+
@NonNull
private RippleAnimationSession.AnimationProperties<Float, Paint> createAnimationProperties(
float x, float y, float cx, float cy, float w, float h) {
Paint p = new Paint(mRipplePaint);
- float radius = mState.mMaxRadius;
+ float radius = getComputedRadius();
RippleAnimationSession.AnimationProperties<Float, Paint> properties;
RippleShader shader = new RippleShader();
int color = mMaskColorFilter == null
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index a9b2447..4608d02 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -71,7 +71,8 @@
+ " float thickness = 0.3 * radius;\n"
+ " float currentRadius = radius * progress;\n"
+ " float circle_outer = softCircle(uv, xy, currentRadius + thickness, blur);\n"
- + " float circle_inner = softCircle(uv, xy, currentRadius - thickness, blur);\n"
+ + " float circle_inner = softCircle(uv, xy, max(currentRadius - thickness, 0.), "
+ + " blur);\n"
+ " return saturate(circle_outer - circle_inner);\n"
+ "}\n"
+ "float subProgress(float start, float end, float progress) {\n"
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 1f9022b..a6aa4f2 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -353,7 +353,7 @@
boolean userPresenceRequired,
byte[] attestationChallenge,
boolean devicePropertiesAttestationIncluded,
- int[] attestationIds,
+ @NonNull int[] attestationIds,
boolean uniqueIdIncluded,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
@@ -779,9 +779,8 @@
* @return integer array representing the requested device IDs to attest.
*/
@SystemApi
- @Nullable
- public int[] getAttestationIds() {
- return Utils.cloneIfNotNull(mAttestationIds);
+ public @NonNull int[] getAttestationIds() {
+ return mAttestationIds.clone();
}
/**
@@ -911,7 +910,7 @@
private boolean mUserPresenceRequired = false;
private byte[] mAttestationChallenge = null;
private boolean mDevicePropertiesAttestationIncluded = false;
- private int[] mAttestationIds = null;
+ private int[] mAttestationIds = new int[0];
private boolean mUniqueIdIncluded = false;
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index c26d9f583..dc7f3dd 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -655,7 +655,7 @@
}
int[] idTypes = mSpec.getAttestationIds();
- if (idTypes == null) {
+ if (idTypes.length == 0) {
return;
}
final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java
new file mode 100644
index 0000000..1302461
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java
@@ -0,0 +1,91 @@
+/*
+ * 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.wm.shell.onehanded;
+
+import android.content.Context;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.annotation.NonNull;
+
+import com.android.wm.shell.R;
+
+import java.io.PrintWriter;
+
+/**
+ * The util for handling A11y events.
+ */
+public final class OneHandedAccessibilityUtil {
+ private static final String TAG = "OneHandedAccessibilityUtil";
+
+ private final AccessibilityManager mAccessibilityManager;
+ private final String mStartOneHandedDescription;
+ private final String mStopOneHandedDescription;
+ private final String mPackageName;
+
+ private String mDescription;
+
+ public OneHandedAccessibilityUtil(Context context) {
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
+ mPackageName = context.getPackageName();
+ mStartOneHandedDescription = context.getResources().getString(
+ R.string.accessibility_action_start_one_handed);
+ mStopOneHandedDescription = context.getResources().getString(
+ R.string.accessibility_action_stop_one_handed);
+ }
+
+ /**
+ * Gets One-Handed start description.
+ * @return text of start description.
+ */
+ public String getOneHandedStartDescription() {
+ return mStartOneHandedDescription;
+ }
+
+ /**
+ * Gets One-Handed stop description.
+ * @return text of stop description.
+ */
+ public String getOneHandedStopDescription() {
+ return mStopOneHandedDescription;
+ }
+
+ /**
+ * Announcement of A11y Events
+ * @param description for accessibility announcement text
+ */
+ public void announcementForScreenReader(String description) {
+ if (!mAccessibilityManager.isTouchExplorationEnabled()) {
+ return;
+ }
+ mDescription = description;
+ final AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setPackageName(mPackageName);
+ event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ event.getText().add(mDescription);
+ mAccessibilityManager.sendAccessibilityEvent(event);
+ }
+
+ public void dump(@NonNull PrintWriter pw) {
+ final String innerPrefix = " ";
+ pw.println(TAG + "States: ");
+ pw.print(innerPrefix + "mPackageName=");
+ pw.println(mPackageName);
+ pw.print(innerPrefix + "mDescription=");
+ pw.println(mDescription);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 38cf9e6..19098fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -83,6 +83,7 @@
private final AccessibilityManager mAccessibilityManager;
private final DisplayController mDisplayController;
private final OneHandedSettingsUtil mOneHandedSettingsUtil;
+ private final OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
private final OneHandedTimeoutHandler mTimeoutHandler;
private final OneHandedTouchHandler mTouchHandler;
private final OneHandedTutorialHandler mTutorialHandler;
@@ -193,6 +194,8 @@
return null;
}
+ OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil();
+ OneHandedAccessibilityUtil accessibilityUtil = new OneHandedAccessibilityUtil(context);
OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
windowManager, mainExecutor);
@@ -205,16 +208,16 @@
OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer =
new OneHandedBackgroundPanelOrganizer(context, displayLayout, mainExecutor);
OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
- context, displayLayout, animationController, tutorialHandler,
+ context, displayLayout, settingsUtil, animationController, tutorialHandler,
oneHandedBackgroundPanelOrganizer, mainExecutor);
- OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil();
OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
return new OneHandedController(context, displayController,
oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
- gestureHandler, settingsUtil, timeoutHandler, oneHandedUiEventsLogger,
- overlayManager, taskStackListener, mainExecutor, mainHandler);
+ gestureHandler, settingsUtil, accessibilityUtil, timeoutHandler,
+ oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor,
+ mainHandler);
}
@VisibleForTesting
@@ -226,6 +229,7 @@
OneHandedTutorialHandler tutorialHandler,
OneHandedGestureHandler gestureHandler,
OneHandedSettingsUtil settingsUtil,
+ OneHandedAccessibilityUtil oneHandedAccessibilityUtil,
OneHandedTimeoutHandler timeoutHandler,
OneHandedUiEventLogger uiEventsLogger,
IOverlayManager overlayManager,
@@ -234,6 +238,7 @@
Handler mainHandler) {
mContext = context;
mOneHandedSettingsUtil = settingsUtil;
+ mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil;
mBackgroundPanelOrganizer = backgroundPanelOrganizer;
mDisplayAreaOrganizer = displayAreaOrganizer;
mDisplayController = displayController;
@@ -334,6 +339,8 @@
if (!mDisplayAreaOrganizer.isInOneHanded()) {
final int yOffSet = Math.round(
mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);
+ mOneHandedAccessibilityUtil.announcementForScreenReader(
+ mOneHandedAccessibilityUtil.getOneHandedStartDescription());
mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
mTimeoutHandler.resetTimer();
@@ -345,6 +352,8 @@
@VisibleForTesting
void stopOneHanded() {
if (mDisplayAreaOrganizer.isInOneHanded()) {
+ mOneHandedAccessibilityUtil.announcementForScreenReader(
+ mOneHandedAccessibilityUtil.getOneHandedStopDescription());
mDisplayAreaOrganizer.scheduleOffset(0, 0);
mTimeoutHandler.removeTimer();
}
@@ -352,6 +361,8 @@
private void stopOneHanded(int uiEvent) {
if (mDisplayAreaOrganizer.isInOneHanded()) {
+ mOneHandedAccessibilityUtil.announcementForScreenReader(
+ mOneHandedAccessibilityUtil.getOneHandedStopDescription());
mDisplayAreaOrganizer.scheduleOffset(0, 0);
mTimeoutHandler.removeTimer();
mOneHandedUiEventLogger.writeEvent(uiEvent);
@@ -629,6 +640,10 @@
mTutorialHandler.dump(pw);
}
+ if (mOneHandedAccessibilityUtil != null) {
+ mOneHandedAccessibilityUtil.dump(pw);
+ }
+
mOneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver(), mUserId);
if (mOverlayManager != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 682c9a3f..d1b3f1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.onehanded;
+import static android.os.UserHandle.myUserId;
+
import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT;
import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER;
@@ -61,6 +63,7 @@
private final Rect mLastVisualDisplayBounds = new Rect();
private final Rect mDefaultDisplayBounds = new Rect();
+ private final OneHandedSettingsUtil mOneHandedSettingsUtil;
private boolean mIsInOneHanded;
private int mEnterExitAnimationDurationMs;
@@ -109,12 +112,14 @@
*/
public OneHandedDisplayAreaOrganizer(Context context,
DisplayLayout displayLayout,
+ OneHandedSettingsUtil oneHandedSettingsUtil,
OneHandedAnimationController animationController,
OneHandedTutorialHandler tutorialHandler,
OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer,
ShellExecutor mainExecutor) {
super(mainExecutor);
mDisplayLayout.set(displayLayout);
+ mOneHandedSettingsUtil = oneHandedSettingsUtil;
updateDisplayBounds();
mAnimationController = animationController;
final int animationDurationConfig = context.getResources().getInteger(
@@ -168,6 +173,11 @@
if (mDisplayLayout.rotation() == toRotation) {
return;
}
+
+ if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(context.getContentResolver(),
+ myUserId())) {
+ return;
+ }
mDisplayLayout.rotateTo(context.getResources(), toRotation);
resetWindowsOffset(wct);
updateDisplayBounds();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index d539835..b445917 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -28,8 +28,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -51,7 +49,6 @@
"persist.debug.one_handed_offset_percentage";
private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
private final WindowManager mWindowManager;
- private final AccessibilityManager mAccessibilityManager;
private final String mPackageName;
private final Rect mDisplaySize;
@@ -59,8 +56,6 @@
private View mTutorialView;
private ContentResolver mContentResolver;
private boolean mCanShowTutorial;
- private String mStartOneHandedDescription;
- private String mStopOneHandedDescription;
private boolean mIsOneHandedMode;
private enum ONE_HANDED_TRIGGER_STATE {
@@ -106,11 +101,6 @@
mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds();
mPackageName = context.getPackageName();
mContentResolver = context.getContentResolver();
- mAccessibilityManager = AccessibilityManager.getInstance(context);
- mStartOneHandedDescription = context.getResources().getString(
- R.string.accessibility_action_start_one_handed);
- mStopOneHandedDescription = context.getResources().getString(
- R.string.accessibility_action_stop_one_handed);
mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
? false : true;
@@ -131,14 +121,12 @@
public void onStartFinished(Rect bounds) {
updateFinished(View.VISIBLE, 0f);
updateTutorialCount();
- announcementForScreenReader(true);
mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
}
@Override
public void onStopFinished(Rect bounds) {
updateFinished(View.INVISIBLE, -mTargetViewContainer.getHeight());
- announcementForScreenReader(false);
removeTutorialFromWindowManager();
mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
}
@@ -170,17 +158,6 @@
Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount);
}
- private void announcementForScreenReader(boolean isStartOneHanded) {
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- final AccessibilityEvent event = AccessibilityEvent.obtain();
- event.setPackageName(mPackageName);
- event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
- event.getText().add(isStartOneHanded
- ? mStartOneHandedDescription : mStopOneHandedDescription);
- mAccessibilityManager.sendAccessibilityEvent(event);
- }
- }
-
/**
* Adds the tutorial target view to the WindowManager and update its layout, so it's ready
* to be animated in.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index e309f96..105bd82 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -58,6 +58,7 @@
Display mDisplay;
DisplayLayout mDisplayLayout;
+ OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
OneHandedController mSpiedOneHandedController;
OneHandedTimeoutHandler mSpiedTimeoutHandler;
@@ -116,6 +117,7 @@
new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()));
when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mDisplayLayout);
+ mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext);
mSpiedOneHandedController = spy(new OneHandedController(
mContext,
mMockDisplayController,
@@ -125,6 +127,7 @@
mMockTutorialHandler,
mMockGestureHandler,
mMockSettingsUitl,
+ mOneHandedAccessibilityUtil,
mSpiedTimeoutHandler,
mMockUiEventLogger,
mMockOverlayManager,
@@ -139,8 +142,8 @@
final OneHandedAnimationController animationController = new OneHandedAnimationController(
mContext);
OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
- mContext, mDisplayLayout, animationController, mMockTutorialHandler,
- mMockBackgroundOrganizer, mMockShellMainExecutor);
+ mContext, mDisplayLayout, mMockSettingsUitl, animationController,
+ mMockTutorialHandler, mMockBackgroundOrganizer, mMockShellMainExecutor);
assertThat(displayAreaOrganizer.isInOneHanded()).isFalse();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
index f654bb5..eb731d2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -97,9 +97,13 @@
OneHandedBackgroundPanelOrganizer mMockBackgroundOrganizer;
@Mock
ShellExecutor mMockShellMainExecutor;
+ @Mock
+ OneHandedSettingsUtil mMockSettingsUitl;
List<DisplayAreaAppearedInfo> mDisplayAreaAppearedInfoList = new ArrayList<>();
+ final boolean mDefaultEnabled = true;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -126,9 +130,12 @@
when(mMockAnimator.setTransitionDirection(anyInt())).thenReturn(mFakeAnimator);
when(mMockLeash.getWidth()).thenReturn(DISPLAY_WIDTH);
when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT);
+ when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(
+ mDefaultEnabled);
mSpiedDisplayAreaOrganizer = spy(new OneHandedDisplayAreaOrganizer(mContext,
mDisplayLayout,
+ mMockSettingsUitl,
mMockAnimationController,
mTutorialHandler,
mMockBackgroundOrganizer,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 2886bb1..06a6671 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -66,6 +66,8 @@
OneHandedUiEventLogger mMockUiEventLogger;
@Mock
OneHandedSettingsUtil mMockSettingsUtil;
+ @Mock
+ OneHandedAccessibilityUtil mMockAccessibilityUtil;
@Before
public void setUp() {
@@ -82,6 +84,7 @@
mMockTutorialHandler,
mMockGestureHandler,
mMockSettingsUtil,
+ mMockAccessibilityUtil,
mTimeoutHandler,
mMockUiEventLogger,
mMockOverlayManager,
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index eedb996..24f553f 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -324,6 +324,8 @@
public static final int ENCODING_MPEGH_LC_L3 = 25;
/** Audio data format: MPEG-H low complexity profile, level 4 */
public static final int ENCODING_MPEGH_LC_L4 = 26;
+ /** Audio data format: DTS UHD compressed */
+ public static final int ENCODING_DTS_UHD = 27;
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
@@ -380,6 +382,8 @@
return "ENCODING_MPEGH_LC_L3";
case ENCODING_MPEGH_LC_L4:
return "ENCODING_MPEGH_LC_L4";
+ case ENCODING_DTS_UHD:
+ return "ENCODING_DTS_UHD";
default :
return "invalid encoding " + enc;
}
@@ -615,6 +619,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return true;
default:
return false;
@@ -650,6 +655,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return true;
default:
return false;
@@ -688,6 +694,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return false;
case ENCODING_INVALID:
default:
@@ -726,6 +733,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return false;
case ENCODING_INVALID:
default:
@@ -1012,6 +1020,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -1238,7 +1247,8 @@
ENCODING_MPEGH_BL_L3,
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
- ENCODING_MPEGH_LC_L4 }
+ ENCODING_MPEGH_LC_L4,
+ ENCODING_DTS_UHD }
)
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
@@ -1258,6 +1268,7 @@
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
ENCODING_MPEGH_LC_L4,
+ ENCODING_DTS_UHD
};
/** @hide */
@@ -1274,7 +1285,8 @@
ENCODING_MPEGH_BL_L3,
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
- ENCODING_MPEGH_LC_L4 }
+ ENCODING_MPEGH_LC_L4,
+ ENCODING_DTS_UHD }
)
@Retention(RetentionPolicy.SOURCE)
public @interface SurroundSoundEncoding {}
@@ -1316,6 +1328,8 @@
return "MPEG-H 3D Audio low complexity profile level 3";
case ENCODING_MPEGH_LC_L4:
return "MPEG-H 3D Audio low complexity profile level 4";
+ case ENCODING_DTS_UHD:
+ return "DTS UHD";
default:
return "Unknown surround sound format";
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 7220379..5f60fb6 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -428,6 +428,8 @@
return "AUDIO_FORMAT_MAT_2_0"; // (MAT | MAT_SUB_2_0)
case /* AUDIO_FORMAT_MAT_2_1 */ 0x24000003:
return "AUDIO_FORMAT_MAT_2_1"; // (MAT | MAT_SUB_2_1)
+ case /* AUDIO_FORMAT_DTS_UHD */ 0x2E000000:
+ return "AUDIO_FORMAT_DTS_UHD";
default:
return "AUDIO_FORMAT_(" + audioFormat + ")";
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 9566b92..5bb4fbc 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -79,6 +79,7 @@
"libgui",
"libharfbuzz_ng", // Only for including hb.h via minikin
"libsensor",
+ "libactivitymanager_aidl",
"libandroid_runtime",
"libminikin",
"libnetd_client",
diff --git a/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java b/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
index 5a76cd6..2bb006d 100644
--- a/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
+++ b/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
@@ -40,6 +40,23 @@
*/
@SystemApi
public final class OemNetworkPreferences implements Parcelable {
+ // Valid production preferences must be > 0, negative values reserved for testing
+ /**
+ * This preference is only to be used for testing and nothing else.
+ * Use only TRANSPORT_TEST transport networks.
+ * @hide
+ */
+ public static final int OEM_NETWORK_PREFERENCE_TEST_ONLY = -2;
+
+ /**
+ * This preference is only to be used for testing and nothing else.
+ * If an unmetered network is available, use it.
+ * Otherwise, if a network with the TRANSPORT_TEST transport is available, use it.
+ * Otherwise, use the general default network.
+ * @hide
+ */
+ public static final int OEM_NETWORK_PREFERENCE_TEST = -1;
+
/**
* Default in case this value is not set. Using it will result in an error.
*/
@@ -69,6 +86,12 @@
*/
public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4;
+ /**
+ * The max allowed value for an OEM network preference.
+ * @hide
+ */
+ public static final int OEM_NETWORK_PREFERENCE_MAX = OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+
@NonNull
private final Bundle mNetworkMappings;
@@ -96,7 +119,7 @@
@Override
public String toString() {
- return "OemNetworkPreferences{" + "mNetworkMappings=" + mNetworkMappings + '}';
+ return "OemNetworkPreferences{" + "mNetworkMappings=" + getNetworkPreferences() + '}';
}
@Override
@@ -185,6 +208,8 @@
/** @hide */
@IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
+ OEM_NETWORK_PREFERENCE_TEST_ONLY,
+ OEM_NETWORK_PREFERENCE_TEST,
OEM_NETWORK_PREFERENCE_UNINITIALIZED,
OEM_NETWORK_PREFERENCE_OEM_PAID,
OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
@@ -205,6 +230,10 @@
@NonNull
public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
switch (value) {
+ case OEM_NETWORK_PREFERENCE_TEST_ONLY:
+ return "OEM_NETWORK_PREFERENCE_TEST_ONLY";
+ case OEM_NETWORK_PREFERENCE_TEST:
+ return "OEM_NETWORK_PREFERENCE_TEST";
case OEM_NETWORK_PREFERENCE_UNINITIALIZED:
return "OEM_NETWORK_PREFERENCE_UNINITIALIZED";
case OEM_NETWORK_PREFERENCE_OEM_PAID:
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index 518f198..20ccf06 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -113,7 +113,6 @@
],
jarjar_rules: "jarjar-rules.txt",
apex_available: [
- "//apex_available:platform", // For arc-services
"com.android.tethering",
],
}
diff --git a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
index b0a9b95..397b0f9 100644
--- a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
+++ b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
@@ -165,9 +165,8 @@
}
private List<EmergencyNumber> getPromotedEmergencyNumbers(int categories) {
- // TODO(b/171542607): Use platform API when its bug is fixed.
- Map<Integer, List<EmergencyNumber>> allLists = filterEmergencyNumbersByCategories(
- mTelephonyManager.getEmergencyNumberList(), categories);
+ Map<Integer, List<EmergencyNumber>> allLists = mTelephonyManager.getEmergencyNumberList(
+ categories);
if (allLists == null || allLists.isEmpty()) {
Log.w(TAG, "Unable to retrieve emergency number lists!");
return new ArrayList<>();
@@ -212,28 +211,4 @@
}
return promotedEmergencyNumberLists.get(SubscriptionManager.getDefaultSubscriptionId());
}
-
- /**
- * Filter emergency numbers with categories.
- */
- private Map<Integer, List<EmergencyNumber>> filterEmergencyNumbersByCategories(
- Map<Integer, List<EmergencyNumber>> emergencyNumberList, int categories) {
- Map<Integer, List<EmergencyNumber>> filteredMap = new ArrayMap<>();
- if (emergencyNumberList == null) {
- return filteredMap;
- }
- for (Integer subscriptionId : emergencyNumberList.keySet()) {
- List<EmergencyNumber> allNumbersForSub = emergencyNumberList.get(
- subscriptionId);
- List<EmergencyNumber> numbersForCategoriesPerSub = new ArrayList<>();
- for (EmergencyNumber number : allNumbersForSub) {
- if (number.isInEmergencyServiceCategories(categories)) {
- numbersForCategoriesPerSub.add(number);
- }
- }
- filteredMap.put(
- subscriptionId, numbersForCategoriesPerSub);
- }
- return filteredMap;
- }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
index 695b5b6..40339de 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
@@ -23,6 +23,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
@@ -126,7 +127,7 @@
List<EmergencyNumber> numbersForSubId = new ArrayList<>();
numbersForSubId.add(emergencyNumber);
numbers.put(subId, numbersForSubId);
- when(mTelephonyManager.getEmergencyNumberList()).thenReturn(numbers);
+ when(mTelephonyManager.getEmergencyNumberList(anyInt())).thenReturn(numbers);
when(emergencyNumber.getNumber()).thenReturn(TELEPHONY_EMERGENCY_NUMBER);
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 5a3298d..16937b7 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -176,6 +176,7 @@
<uses-permission android:name="android.permission.SET_TIME_ZONE" />
<uses-permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS" />
<uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
+ <uses-permission android:name="android.permission.BYPASS_ROLE_QUALIFICATION" />
<uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.STATUS_BAR" />
@@ -265,10 +266,11 @@
<!-- permissions required for CTS test - PhoneStateListenerTest -->
<uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
- <!-- Permissions required for ganting and logging -->
+ <!-- Permissions required for granting and logging -->
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
<uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
<!-- Permission required for CTS test - BatterySaverTest -->
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 88d7710..85ecb1c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -275,8 +275,6 @@
<!-- Permission to make accessibility service access Bubbles -->
<uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" />
- <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
-
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 35423a9..f8a9a045 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -16,9 +16,7 @@
package com.android.systemui.plugins;
-import android.app.smartspace.SmartspaceTarget;
import android.os.Parcelable;
-import android.view.ViewGroup;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -38,25 +36,9 @@
/** Unregister a listener. */
void unregisterListener(SmartspaceTargetListener listener);
- /**
- * Create a view to be shown within the parent. Do not add the view, as the parent
- * will be responsible for correctly setting the LayoutParams
- */
- default SmartspaceView getView(ViewGroup parent) {
- return null;
- }
-
- /** Updates Smartspace data and propagates it to any listeners. */
- void onTargetsAvailable(List<SmartspaceTarget> targets);
-
/** Provides Smartspace data to registered listeners. */
interface SmartspaceTargetListener {
/** Each Parcelable is a SmartspaceTarget that represents a card. */
void onSmartspaceTargetsUpdated(List<? extends Parcelable> targets);
}
-
- /** View to which this plugin can be registered, in order to get updates. */
- interface SmartspaceView {
- void registerDataProvider(BcSmartspaceDataPlugin plugin);
- }
}
diff --git a/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml b/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml
new file mode 100644
index 0000000..bdd6270
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="?android:attr/colorAccent" />
+ <corners android:radius="@dimen/ongoing_call_chip_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
new file mode 100644
index 0000000..c90fc31
--- /dev/null
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -0,0 +1,50 @@
+<!--
+ ~ 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/ongoing_call_chip"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/ongoing_appops_chip_height"
+ android:layout_gravity="center_vertical|start"
+ android:gravity="center_vertical"
+ android:background="@drawable/ongoing_call_chip_bg"
+ android:paddingStart="@dimen/ongoing_call_chip_side_padding"
+ android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
+ android:visibility="gone"
+>
+
+ <ImageView
+ android:src="@*android:drawable/ic_phone"
+ android:layout_width="@dimen/ongoing_call_chip_icon_size"
+ android:layout_height="@dimen/ongoing_call_chip_icon_size"
+ android:paddingEnd="@dimen/ongoing_call_chip_icon_text_padding"
+ android:tint="?android:attr/colorPrimary"
+ />
+
+ <!-- TODO(b/183229367): The text in this view isn't quite centered within the chip. -->
+ <!-- TODO(b/183229367): This text view's width shouldn't change as the time increases. -->
+ <Chronometer
+ android:id="@+id/ongoing_call_chip_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textAppearance="@android:style/TextAppearance.Material.Small"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:textColor="?android:attr/colorPrimary"
+ />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f8db97d..8b244c7 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -82,6 +82,8 @@
android:gravity="center_vertical|start"
/>
+ <include layout="@layout/ongoing_call_chip" />
+
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 4fdeb6f..cd2395e 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -29,4 +29,10 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <!-- Screenshots -->
+ <style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <item name="android:windowLightStatusBar">false</item>
+ <item name="android:windowLightNavigationBar">false</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 237edf8..e834f3f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1442,4 +1442,11 @@
<dimen name="wallet_empty_state_corner_radius">24dp</dimen>
<dimen name="wallet_tile_card_view_height">32dp</dimen>
<dimen name="wallet_tile_card_view_width">50dp</dimen>
+
+ <!-- Ongoing call chip -->
+ <dimen name="ongoing_call_chip_side_padding">12dp</dimen>
+ <dimen name="ongoing_call_chip_icon_size">16dp</dimen>
+ <!-- The padding between the icon and the text. -->
+ <dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
+ <dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index c39db94..834b482 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -49,7 +49,5 @@
<bool name="flag_charging_ripple">false</bool>
- <bool name="flag_ongoing_call_status_bar_chip">false</bool>
-
- <bool name="flag_smartspace">false</bool>
+ <bool name="flag_ongoing_call_status_bar_chip">true</bool>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index de14dbd..ba07829 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -623,6 +623,8 @@
<!-- Screenshots -->
<style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="android:windowNoTitle">true</item>
+ <item name="android:windowLightStatusBar">true</item>
+ <item name="android:windowLightNavigationBar">true</item>
</style>
<!-- Privacy dialog -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 24b7cd1..0675200 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -16,15 +16,8 @@
package com.android.keyguard;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
import android.app.WallpaperManager;
-import android.app.smartspace.SmartspaceConfig;
-import android.app.smartspace.SmartspaceManager;
-import android.app.smartspace.SmartspaceSession;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
import android.text.TextUtils;
@@ -32,7 +25,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.RelativeLayout;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
@@ -40,12 +32,8 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -55,7 +43,6 @@
import java.util.Locale;
import java.util.TimeZone;
-import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -81,13 +68,6 @@
private AnimatableClockController mNewLockScreenLargeClockViewController;
private FrameLayout mNewLockScreenLargeClockFrame;
- private PluginManager mPluginManager;
- private boolean mIsSmartspaceEnabled;
- PluginListener mPluginListener;
- private Executor mUiExecutor;
- private SmartspaceSession mSmartspaceSession;
- private SmartspaceSession.Callback mSmartspaceCallback;
-
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
private final StatusBarStateController.StateListener mStateListener =
@@ -116,9 +96,6 @@
private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
private String mTimeFormat;
- // If set, will replace keyguard_status_area
- private BcSmartspaceDataPlugin.SmartspaceView mSmartspaceView;
-
@Inject
public KeyguardClockSwitchController(
KeyguardClockSwitch keyguardClockSwitch,
@@ -128,10 +105,7 @@
KeyguardSliceViewController keyguardSliceViewController,
NotificationIconAreaController notificationIconAreaController,
ContentResolver contentResolver,
- BroadcastDispatcher broadcastDispatcher,
- PluginManager pluginManager,
- FeatureFlags featureFlags,
- @Main Executor uiExecutor) {
+ BroadcastDispatcher broadcastDispatcher) {
super(keyguardClockSwitch);
mResources = resources;
mStatusBarStateController = statusBarStateController;
@@ -141,9 +115,6 @@
mNotificationIconAreaController = notificationIconAreaController;
mBroadcastDispatcher = broadcastDispatcher;
mTimeFormat = Settings.System.getString(contentResolver, Settings.System.TIME_12_24);
- mPluginManager = pluginManager;
- mIsSmartspaceEnabled = featureFlags.isSmartspaceEnabled();
- mUiExecutor = uiExecutor;
}
/**
@@ -166,63 +137,6 @@
updateAodIcons();
mNewLockScreenClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view);
mNewLockScreenLargeClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view_large);
-
- // If a smartspace plugin is detected, replace the existing smartspace
- // (keyguard_status_area), and initialize a new session
- mPluginListener = new PluginListener<BcSmartspaceDataPlugin>() {
-
- @Override
- public void onPluginConnected(BcSmartspaceDataPlugin plugin, Context pluginContext) {
- if (!mIsSmartspaceEnabled) return;
-
- View ksa = mView.findViewById(R.id.keyguard_status_area);
- int ksaIndex = mView.indexOfChild(ksa);
- ksa.setVisibility(View.GONE);
-
- mSmartspaceView = plugin.getView(mView);
- mSmartspaceView.registerDataProvider(plugin);
-
- RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
- MATCH_PARENT, WRAP_CONTENT);
- lp.addRule(RelativeLayout.BELOW, R.id.new_lockscreen_clock_view);
- mView.addView((View) mSmartspaceView, ksaIndex, lp);
-
- View nic = mView.findViewById(
- com.android.systemui.R.id.left_aligned_notification_icon_container);
- lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
- lp.addRule(RelativeLayout.BELOW, ((View) mSmartspaceView).getId());
- nic.setLayoutParams(lp);
-
- createSmartspaceSession(plugin);
- }
-
- @Override
- public void onPluginDisconnected(BcSmartspaceDataPlugin plugin) {
- if (!mIsSmartspaceEnabled) return;
-
- mView.removeView((View) mSmartspaceView);
- mView.findViewById(R.id.keyguard_status_area).setVisibility(View.VISIBLE);
-
- View nic = mView.findViewById(
- com.android.systemui.R.id.left_aligned_notification_icon_container);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)
- nic.getLayoutParams();
- lp.addRule(RelativeLayout.BELOW, R.id.keyguard_status_area);
- nic.setLayoutParams(lp);
-
- mSmartspaceView = null;
- }
-
- private void createSmartspaceSession(BcSmartspaceDataPlugin plugin) {
- mSmartspaceSession = getContext().getSystemService(SmartspaceManager.class)
- .createSmartspaceSession(
- new SmartspaceConfig.Builder(getContext(), "lockscreen").build());
- mSmartspaceCallback = targets -> plugin.onTargetsAvailable(targets);
- mSmartspaceSession.registerSmartspaceUpdates(mUiExecutor, mSmartspaceCallback);
- mSmartspaceSession.requestSmartspaceUpdate();
- }
- };
- mPluginManager.addPluginListener(mPluginListener, BcSmartspaceDataPlugin.class, false);
}
@Override
@@ -233,13 +147,6 @@
mStatusBarStateController.removeCallback(mStateListener);
mColorExtractor.removeOnColorsChangedListener(mColorsListener);
mView.setClockPlugin(null, mStatusBarStateController.getState());
-
- if (mSmartspaceSession != null) {
- mSmartspaceSession.unregisterSmartspaceUpdates(mSmartspaceCallback);
- mSmartspaceSession.destroy();
- mSmartspaceSession = null;
- }
- mPluginManager.removePluginListener(mPluginListener);
}
/**
@@ -315,11 +222,6 @@
PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_Y,
scale, props, animate);
}
-
- if (mSmartspaceView != null) {
- PropertyAnimator.setProperty((View) mSmartspaceView, AnimatableProperty.TRANSLATION_X,
- x, props, animate);
- }
mKeyguardSliceViewController.updatePosition(x, props, animate);
mNotificationIconAreaController.updatePosition(x, props, animate);
}
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index 2eba952..c23bcb8 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -40,6 +40,7 @@
new PathInterpolator(0.8f, 0f, 0.6f, 1f);
public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+ public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
public static final Interpolator LINEAR = new LinearInterpolator();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index cc167b9..9d00262 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -46,7 +46,6 @@
private GlobalRootComponent mRootComponent;
private WMComponent mWMComponent;
private SysUIComponent mSysUIComponent;
- private boolean mInitializeComponents;
public static <T extends SystemUIFactory> T getInstance() {
return (T) mFactory;
@@ -89,13 +88,13 @@
public void init(Context context, boolean fromTest)
throws ExecutionException, InterruptedException {
// Only initialize components for the main system ui process running as the primary user
- mInitializeComponents = !fromTest
+ final boolean initializeComponents = !fromTest
&& android.os.Process.myUserHandle().isSystem()
&& ActivityThread.currentProcessName().equals(ActivityThread.currentPackageName());
mRootComponent = buildGlobalRootComponent(context);
// Stand up WMComponent
mWMComponent = mRootComponent.getWMComponentBuilder().build();
- if (mInitializeComponents) {
+ if (initializeComponents) {
// Only initialize when not starting from tests since this currently initializes some
// components that shouldn't be run in the test environment
mWMComponent.init();
@@ -103,7 +102,7 @@
// And finally, retrieve whatever SysUI needs from WMShell and build SysUI.
SysUIComponent.Builder builder = mRootComponent.getSysUIComponent();
- if (mInitializeComponents) {
+ if (initializeComponents) {
// Only initialize when not starting from tests since this currently initializes some
// components that shouldn't be run in the test environment
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
@@ -135,7 +134,7 @@
.setStartingSurface(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
- if (mInitializeComponents) {
+ if (initializeComponents) {
mSysUIComponent.init();
}
@@ -161,9 +160,6 @@
.build();
}
- protected boolean shouldInitializeComponents() {
- return mInitializeComponents;
- }
public GlobalRootComponent getRootComponent() {
return mRootComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index 4dd8780..6a012eb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -38,8 +38,10 @@
public static final int BOUNCER_UNLOCK = 8;
public static final int PULSE_EXPAND = 9;
public static final int BRIGHTNESS_SLIDER = 10;
- public static final int UDFPS_AUTHENTICATION = 11;
- public static final int DISABLED_UDFPS_AFFORDANCE = 12;
+ public static final int SHADE_DRAG = 11;
+ public static final int QS_COLLAPSE = 12;
+ public static final int UDFPS_AUTHENTICATION = 13;
+ public static final int DISABLED_UDFPS_AFFORDANCE = 14;
@IntDef({
QUICK_SETTINGS,
@@ -53,6 +55,9 @@
BOUNCER_UNLOCK,
PULSE_EXPAND,
BRIGHTNESS_SLIDER,
+ SHADE_DRAG,
+ QS_COLLAPSE,
+ BRIGHTNESS_SLIDER,
UDFPS_AUTHENTICATION,
DISABLED_UDFPS_AFFORDANCE
})
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 6a70622..a4e1637 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -22,6 +22,9 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN;
+import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
+import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
@@ -148,7 +151,9 @@
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
- if (interactionType == Classifier.BRIGHTNESS_SLIDER
+ if (interactionType == BRIGHTNESS_SLIDER
+ || interactionType == SHADE_DRAG
+ || interactionType == QS_COLLAPSE
|| interactionType == Classifier.UDFPS_AUTHENTICATION
|| interactionType == Classifier.DISABLED_UDFPS_AFFORDANCE) {
return Result.passed(0);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 6f80010..3bc24c7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -18,6 +18,7 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.provider.DeviceConfig;
@@ -116,7 +117,8 @@
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
- if (interactionType == QUICK_SETTINGS || interactionType == BRIGHTNESS_SLIDER) {
+ if (interactionType == QUICK_SETTINGS || interactionType == BRIGHTNESS_SLIDER
+ || interactionType == QS_COLLAPSE) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index 50e94b3..1042516 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -23,8 +23,10 @@
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
import static com.android.systemui.classifier.Classifier.PULSE_EXPAND;
+import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
+import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
import static com.android.systemui.classifier.Classifier.UNLOCK;
import javax.inject.Inject;
@@ -77,6 +79,12 @@
case RIGHT_AFFORDANCE: // Swiping from the bottom right corner for camera or similar.
wrongDirection = right || !up;
break;
+ case SHADE_DRAG:
+ wrongDirection = !vertical;
+ break;
+ case QS_COLLAPSE:
+ wrongDirection = !vertical || !up;
+ break;
default:
wrongDirection = true;
break;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index d9197ef..e1349f2 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -21,6 +21,7 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
import android.graphics.Point;
import android.provider.DeviceConfig;
@@ -88,7 +89,7 @@
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
- if (interactionType == BRIGHTNESS_SLIDER) {
+ if (interactionType == BRIGHTNESS_SLIDER || interactionType == SHADE_DRAG) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index 7a8b2c6..b953323 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -118,7 +118,11 @@
override fun setClickable(clickable: Boolean) {
super.setClickable(clickable)
background = if (clickable && mShowRippleEffect) {
- mTileBackground
+ mRipple?.also {
+ // In case that the colorBackgroundDrawable was used as the background, make sure
+ // it has the correct callback instead of null
+ colorBackgroundDrawable?.callback = it
+ }
} else {
colorBackgroundDrawable
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 7ef88bb..5cebf7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -142,9 +142,9 @@
}
return true;
case MotionEvent.ACTION_UP:
- if (!mFalsingManager.isUnlockingDisabled() && !isFalseTouch()
- && mDragDownCallback.onDraggedDown(mStartingChild,
- (int) (y - mInitialTouchY))) {
+ if (!mFalsingManager.isUnlockingDisabled() && mDragDownCallback.canDragDown()
+ && !isFalseTouch()) {
+ mDragDownCallback.onDraggedDown(mStartingChild, (int) (y - mInitialTouchY));
if (mStartingChild == null) {
cancelExpansion();
} else {
@@ -263,7 +263,10 @@
/**
* @return true if the interaction is accepted, false if it should be cancelled
*/
- boolean onDraggedDown(View startingChild, int dragLengthY);
+ boolean canDragDown();
+
+ /** Call when a view has been dragged. */
+ void onDraggedDown(View startingChild, int dragLengthY);
void onDragDownReset();
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index ec3a857..f51fbed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -97,8 +97,4 @@
public boolean isOngoingCallStatusBarChipEnabled() {
return mFlagReader.isEnabled(R.bool.flag_ongoing_call_status_bar_chip);
}
-
- public boolean isSmartspaceEnabled() {
- return mFlagReader.isEnabled(R.bool.flag_smartspace);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 14c73b5..20383fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -63,6 +63,7 @@
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
@@ -234,9 +235,11 @@
@Provides
@SysUISingleton
static OngoingCallController provideOngoingCallController(
- CommonNotifCollection notifCollection, FeatureFlags featureFlags) {
+ CommonNotifCollection notifCollection,
+ FeatureFlags featureFlags,
+ SystemClock systemClock) {
OngoingCallController ongoingCallController =
- new OngoingCallController(notifCollection, featureFlags);
+ new OngoingCallController(notifCollection, featureFlags, systemClock);
ongoingCallController.init();
return ongoingCallController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 18e5ead..17f70cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -720,6 +720,10 @@
mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
mCurrentAlphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
targetValue = 1.0f;
+ if (!mIsHeadsUpAnimation && isChildInGroup()) {
+ // slower fade in of children to avoid visibly overlapping with other children
+ mCurrentAlphaInterpolator = Interpolators.SLOW_OUT_LINEAR_IN;
+ }
} else {
mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN;
mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
@@ -819,6 +823,10 @@
if (mIsHeadsUpAnimation && !mIsAppearing) {
startWidthFraction = 0;
}
+ if (mIsAppearing && !mIsHeadsUpAnimation && isChildInGroup()) {
+ // Children in a group (when not heads up) should simply fade in.
+ startWidthFraction = 1;
+ }
float width = MathUtils.lerp(startWidthFraction, 1.0f, 1.0f - widthFraction)
* getWidth();
float left;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ad06e7d..b28cc14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -5499,9 +5499,16 @@
@ShadeViewRefactor(RefactorComponent.INPUT)
private final DragDownCallback mDragDownCallback = new DragDownCallback() {
+ @Override
+ public boolean canDragDown() {
+ return mStatusBarState == StatusBarState.KEYGUARD
+ && (mController.hasActiveNotifications() || mKeyguardMediaControllorVisible)
+ || mController.isInLockedDownShade();
+ }
+
/* Only ever called as a consequence of a lockscreen expansion gesture. */
@Override
- public boolean onDraggedDown(View startingChild, int dragLengthY) {
+ public void onDraggedDown(View startingChild, int dragLengthY) {
boolean canDragDown =
mController.hasActiveNotifications() || mKeyguardMediaControllorVisible;
if (mStatusBarState == StatusBarState.KEYGUARD && canDragDown) {
@@ -5519,16 +5526,10 @@
row.onExpandedByGesture(true /* drag down is always an open */);
}
}
-
- return true;
} else if (mController.isInLockedDownShade()) {
mStatusbarStateController.setLeaveOpenOnKeyguardHide(true);
mStatusBar.dismissKeyguardThenExecute(() -> false /* dismissAction */,
null /* cancelRunnable */, false /* afterKeyguardGone */);
- return true;
- } else {
- // abort gesture.
- return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index ce7b397..7776e69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -59,10 +59,12 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -143,6 +145,7 @@
private final ZenModeController mZenModeController;
private final MetricsLogger mMetricsLogger;
private final FalsingCollector mFalsingCollector;
+ private final FalsingManager mFalsingManager;
private final Resources mResources;
private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
private final ScrimController mScrimController;
@@ -556,6 +559,7 @@
NotificationLockscreenUserManager lockscreenUserManager,
MetricsLogger metricsLogger,
FalsingCollector falsingCollector,
+ FalsingManager falsingManager,
@Main Resources resources,
NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
StatusBar statusBar,
@@ -589,6 +593,7 @@
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
mFalsingCollector = falsingCollector;
+ mFalsingManager = falsingManager;
mResources = resources;
mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
mStatusBar = statusBar;
@@ -1614,6 +1619,9 @@
}
}
if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ // Ensure the falsing manager records the touch. we don't do anything with it
+ // at the moment.
+ mFalsingManager.isFalseTouch(Classifier.SHADE_DRAG);
mView.setCheckForLeaveBehind(true);
}
traceJankOnTouchEvent(ev.getActionMasked(), scrollerWantsIt);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index f64a0e0..9d1c609 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import com.android.systemui.statusbar.policy.EncryptionHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -67,6 +68,7 @@
private NetworkController mNetworkController;
private LinearLayout mSystemIconArea;
private View mClockView;
+ private ViewGroup mOngoingCallChip;
private View mNotificationIconAreaInner;
private View mCenteredIconArea;
private int mDisabled1;
@@ -86,6 +88,20 @@
}
};
+ private final OngoingCallListener mOngoingCallListener = new OngoingCallListener() {
+ @Override
+ public void onOngoingCallStarted(boolean animate) {
+ disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
+ animateShow(mOngoingCallChip, animate);
+ }
+
+ @Override
+ public void onOngoingCallEnded(boolean animate) {
+ disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
+ animateHiddenState(mOngoingCallChip, View.GONE, animate);
+ }
+ };
+
@Inject
public CollapsedStatusBarFragment(OngoingCallController ongoingCallController) {
mOngoingCallController = ongoingCallController;
@@ -142,6 +158,7 @@
super.onResume();
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
+ mOngoingCallController.addCallback(mOngoingCallListener);
}
@Override
@@ -149,6 +166,7 @@
super.onPause();
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
+ mOngoingCallController.removeCallback(mOngoingCallListener);
}
@Override
@@ -179,6 +197,8 @@
}
statusBarCenteredIconArea.addView(mCenteredIconArea);
+ initOngoingCallChip();
+
// Default to showing until we know otherwise.
showNotificationIconArea(false);
}
@@ -228,6 +248,10 @@
state |= DISABLE_CLOCK;
}
+ if (mOngoingCallController.getHasOngoingCall()) {
+ state |= DISABLE_NOTIFICATION_ICONS;
+ }
+
if (!mKeyguardStateController.isLaunchTransitionFadingAway()
&& !mKeyguardStateController.isKeyguardFadingAway()
&& shouldHideNotificationIcons()
@@ -395,6 +419,11 @@
}
}
+ private void initOngoingCallChip() {
+ mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
+ mOngoingCallController.setChipView(mOngoingCallChip);
+ }
+
@Override
public void onStateChanged(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 364b532..610369b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -24,6 +24,7 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
+import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
@@ -1450,11 +1451,7 @@
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
trackMovement(event);
- if (mQsTracking) {
- flingQsWithCurrentVelocity(y,
- event.getActionMasked() == MotionEvent.ACTION_CANCEL);
- mQsTracking = false;
- }
+ mQsTracking = false;
break;
}
return false;
@@ -1526,10 +1523,17 @@
private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) {
float vel = getCurrentQSVelocity();
- final boolean expandsQs = flingExpandsQs(vel);
+ boolean expandsQs = flingExpandsQs(vel);
if (expandsQs) {
- logQsSwipeDown(y);
+ if (mFalsingManager.isUnlockingDisabled() || isFalseTouch(QUICK_SETTINGS)) {
+ expandsQs = false;
+ } else {
+ logQsSwipeDown(y);
+ }
+ } else if (vel < 0) {
+ mFalsingManager.isFalseTouch(QS_COLLAPSE);
}
+
flingSettings(vel, expandsQs && !isCancelMotionEvent ? FLING_EXPAND : FLING_COLLAPSE);
}
@@ -1545,9 +1549,6 @@
}
private boolean flingExpandsQs(float vel) {
- if (mFalsingManager.isUnlockingDisabled() || isFalseTouch(QUICK_SETTINGS)) {
- return false;
- }
if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
return getQsExpansionFraction() > 0.5f;
} else {
@@ -1556,9 +1557,6 @@
}
private boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
- if (!mKeyguardAffordanceHelperCallback.needsAntiFalsing()) {
- return false;
- }
if (mFalsingManager.isClassifierEnabled()) {
return mFalsingManager.isFalseTouch(interactionType);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 77abe79..936e289 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -18,6 +18,7 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
+import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.classifier.Classifier.UNLOCK;
@@ -430,9 +431,9 @@
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp);
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
}
- @Classifier.InteractionType int interactionType = vel > 0
- ? QUICK_SETTINGS : (
- mKeyguardStateController.canDismissLockScreen()
+ @Classifier.InteractionType int interactionType = vel == 0 ? GENERIC
+ : vel > 0 ? QUICK_SETTINGS
+ : (mKeyguardStateController.canDismissLockScreen()
? UNLOCK : BOUNCER_UNLOCK);
fling(vel, expand, isFalseTouch(x, y, interactionType));
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 7e433e8..c37ddd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1825,7 +1825,7 @@
}
public boolean isFalsingThresholdNeeded() {
- return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+ return true;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 60d3ea3..b55db6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -19,11 +19,16 @@
import android.app.Notification
import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
import android.util.Log
+import android.view.ViewGroup
+import android.widget.Chronometer
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
/**
@@ -32,19 +37,39 @@
@SysUISingleton
class OngoingCallController @Inject constructor(
private val notifCollection: CommonNotifCollection,
- private val featureFlags: FeatureFlags
-) {
+ private val featureFlags: FeatureFlags,
+ private val systemClock: SystemClock
+) : CallbackController<OngoingCallListener> {
+
+ var hasOngoingCall = false
+ private set
+ private var chipView: ViewGroup? = null
+
+ private val mListeners: MutableList<OngoingCallListener> = mutableListOf()
private val notifListener = object : NotifCollectionListener {
override fun onEntryUpdated(entry: NotificationEntry) {
- if (isOngoingCallNotification(entry) && DEBUG) {
- Log.d(TAG, "Ongoing call notification updated")
+ if (isOngoingCallNotification(entry)) {
+ val timeView = chipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
+ if (timeView != null) {
+ hasOngoingCall = true
+ val callStartTime = entry.sbn.notification.`when`
+ timeView.base = callStartTime -
+ System.currentTimeMillis() +
+ systemClock.elapsedRealtime()
+ timeView.start()
+ mListeners.forEach { l -> l.onOngoingCallStarted(animate = true) }
+ } else if (DEBUG) {
+ Log.w(TAG, "Ongoing call chip view could not be found; " +
+ "Not displaying chip in status bar")
+ }
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
- if (isOngoingCallNotification(entry) && DEBUG) {
- Log.d(TAG, "Ongoing call notification removed")
+ if (isOngoingCallNotification(entry)) {
+ hasOngoingCall = false
+ mListeners.forEach { l -> l.onOngoingCallEnded(animate = true) }
}
}
}
@@ -54,6 +79,24 @@
notifCollection.addCollectionListener(notifListener)
}
}
+
+ fun setChipView(chipView: ViewGroup?) {
+ this.chipView = chipView
+ }
+
+ override fun addCallback(listener: OngoingCallListener) {
+ synchronized(mListeners) {
+ if (!mListeners.contains(listener)) {
+ mListeners.add(listener)
+ }
+ }
+ }
+
+ override fun removeCallback(listener: OngoingCallListener) {
+ synchronized(mListeners) {
+ mListeners.remove(listener)
+ }
+ }
}
private fun isOngoingCallNotification(entry: NotificationEntry): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt
new file mode 100644
index 0000000..7c583a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.systemui.statusbar.phone.ongoingcall
+
+/** A listener that's notified when an ongoing call is started or ended. */
+interface OngoingCallListener {
+ /** Called when an ongoing call is started. */
+ fun onOngoingCallStarted(animate: Boolean)
+
+ /** Called when an ongoing call is ended. */
+ fun onOngoingCallEnded(animate: Boolean)
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 0fcd79b..70a7b7a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -18,34 +18,26 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.res.Resources;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
-import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.RelativeLayout;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
@@ -58,8 +50,6 @@
import org.mockito.MockitoAnnotations;
import org.mockito.verification.VerificationMode;
-import java.util.concurrent.Executor;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@@ -88,12 +78,6 @@
ContentResolver mContentResolver;
@Mock
BroadcastDispatcher mBroadcastDispatcher;
- @Mock
- private PluginManager mPluginManager;
- @Mock
- private FeatureFlags mFeatureFlags;
- @Mock
- private Executor mExecutor;
private KeyguardClockSwitchController mController;
@@ -103,8 +87,6 @@
when(mView.findViewById(com.android.systemui.R.id.left_aligned_notification_icon_container))
.thenReturn(mNotificationIcons);
- when(mView.getContext()).thenReturn(getContext());
- when(mFeatureFlags.isSmartspaceEnabled()).thenReturn(true);
when(mView.isAttachedToWindow()).thenReturn(true);
when(mResources.getString(anyInt())).thenReturn("h:mm");
mController = new KeyguardClockSwitchController(
@@ -116,10 +98,7 @@
mKeyguardSliceViewController,
mNotificationIconAreaController,
mContentResolver,
- mBroadcastDispatcher,
- mPluginManager,
- mFeatureFlags,
- mExecutor);
+ mBroadcastDispatcher);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
@@ -203,45 +182,6 @@
verify(mView).setClockPlugin(mClockPlugin, StatusBarState.SHADE);
}
- @Test
- public void testSmartspacePluginConnectedRemovesKeyguardStatusArea() {
- mController.init();
-
- View statusArea = mock(View.class);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
-
- View nic = mock(View.class);
- when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
- when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
-
- BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
- TestView view = mock(TestView.class);
- when(plugin.getView(any())).thenReturn(view);
-
- mController.mPluginListener.onPluginConnected(plugin, mContext);
- verify(statusArea).setVisibility(View.GONE);
- }
-
- @Test
- public void testSmartspacePluginDisconnectedShowsKeyguardStatusArea() {
- mController.init();
-
- View statusArea = mock(View.class);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
-
- View nic = mock(View.class);
- when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
- when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
-
- BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
- TestView view = mock(TestView.class);
- when(plugin.getView(any())).thenReturn(view);
-
- mController.mPluginListener.onPluginConnected(plugin, mContext);
- mController.mPluginListener.onPluginDisconnected(plugin);
- verify(statusArea).setVisibility(View.VISIBLE);
- }
-
private void verifyAttachment(VerificationMode times) {
verify(mClockManager, times).addOnClockChangedListener(
any(ClockManager.ClockChangedListener.class));
@@ -251,12 +191,4 @@
any(ColorExtractor.OnColorsChangedListener.class));
verify(mView, times).updateColors(mGradientColors);
}
-
- private static class TestView extends View implements BcSmartspaceDataPlugin.SmartspaceView {
- TestView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void registerDataProvider(BcSmartspaceDataPlugin plugin) { }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index 3c4fde8..895339f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -43,6 +43,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -160,6 +161,7 @@
mNotificationLockscreenUserManager,
mMetricsLogger,
new FalsingCollectorFake(),
+ new FalsingManagerFake(),
mResources,
mNotificationSwipeHelperBuilder,
mStatusBar,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 96cdaf9..67fd5eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -38,12 +38,16 @@
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import java.util.Objects;
+
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -53,6 +57,7 @@
private View mNotificationAreaInner;
private View mCenteredNotificationAreaView;
private StatusBarStateController mStatusBarStateController;
+ private OngoingCallController mOngoingCallController;
public CollapsedStatusBarFragmentTest() {
super(CollapsedStatusBarFragment.class);
@@ -162,8 +167,51 @@
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
}
+ @Test
+ public void onOngoingCallStarted_notificationsHiddenAndOngoingCallChipDisplayed() {
+ mFragments.dispatchResume();
+ processAllMessages();
+
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+ fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
+ ArgumentCaptor<OngoingCallListener> ongoingCallListenerCaptor = ArgumentCaptor.forClass(
+ OngoingCallListener.class);
+ Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
+ OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
+
+ when(mOngoingCallController.getHasOngoingCall()).thenReturn(true);
+ listener.onOngoingCallStarted(/* animate= */ false);
+
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
+ }
+
+ @Test
+ public void onOngoingCallEnded_notificationsDisplayedAndOngoingCallChipHidden() {
+ mFragments.dispatchResume();
+ processAllMessages();
+
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+ fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
+ ArgumentCaptor<OngoingCallListener> ongoingCallListenerCaptor = ArgumentCaptor.forClass(
+ OngoingCallListener.class);
+ Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
+ OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
+
+ when(mOngoingCallController.getHasOngoingCall()).thenReturn(false);
+ listener.onOngoingCallEnded(/* animate= */ false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
+ }
+
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
- return new CollapsedStatusBarFragment(mock(OngoingCallController.class));
+ mOngoingCallController = mock(OngoingCallController.class);
+ return new CollapsedStatusBarFragment(mOngoingCallController);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
new file mode 100644
index 0000000..d87d1d1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.systemui.statusbar.phone.ongoingcall
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.Person
+import android.service.notification.NotificationListenerService.REASON_USER_STOPPED
+import androidx.test.filters.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.never
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class OngoingCallControllerTest : SysuiTestCase() {
+
+ private lateinit var controller: OngoingCallController
+ private lateinit var notifCollectionListener: NotifCollectionListener
+
+ @Mock private lateinit var mockOngoingCallListener: OngoingCallListener
+
+ private lateinit var chipView: LinearLayout
+
+ @Before
+ fun setUp() {
+ allowTestableLooperAsMainThread()
+ TestableLooper.get(this).runWithLooper {
+ chipView = LayoutInflater.from(mContext)
+ .inflate(R.layout.ongoing_call_chip, null) as LinearLayout
+ }
+
+ MockitoAnnotations.initMocks(this)
+ val featureFlags = mock(FeatureFlags::class.java)
+ `when`(featureFlags.isOngoingCallStatusBarChipEnabled).thenReturn(true)
+ val notificationCollection = mock(CommonNotifCollection::class.java)
+
+ controller = OngoingCallController(notificationCollection, featureFlags, FakeSystemClock())
+ controller.init()
+ controller.addCallback(mockOngoingCallListener)
+ controller.setChipView(chipView)
+
+ val collectionListenerCaptor = ArgumentCaptor.forClass(NotifCollectionListener::class.java)
+ verify(notificationCollection).addCollectionListener(collectionListenerCaptor.capture())
+ notifCollectionListener = collectionListenerCaptor.value!!
+ }
+
+ @Test
+ fun onEntryUpdated_isOngoingCallNotif_listenerNotifiedWithRightCallTime() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ verify(mockOngoingCallListener).onOngoingCallStarted(anyBoolean())
+ }
+
+ @Test
+ fun onEntryUpdated_notOngoingCallNotif_listenerNotNotified() {
+ notifCollectionListener.onEntryUpdated(createNotCallNotifEntry())
+
+ verify(mockOngoingCallListener, never()).onOngoingCallStarted(anyBoolean())
+ }
+
+ @Test
+ fun onEntryRemoved_ongoingCallNotif_listenerNotified() {
+ notifCollectionListener.onEntryRemoved(createOngoingCallNotifEntry(), REASON_USER_STOPPED)
+
+ verify(mockOngoingCallListener).onOngoingCallEnded(anyBoolean())
+ }
+
+ @Test
+ fun onEntryRemoved_notOngoingCallNotif_listenerNotNotified() {
+ notifCollectionListener.onEntryRemoved(createNotCallNotifEntry(), REASON_USER_STOPPED)
+
+ verify(mockOngoingCallListener, never()).onOngoingCallEnded(anyBoolean())
+ }
+
+ @Test
+ fun hasOngoingCall_noOngoingCallNotifSent_returnsFalse() {
+ assertThat(controller.hasOngoingCall).isFalse()
+ }
+
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentAndChipViewSet_returnsTrue() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ assertThat(controller.hasOngoingCall).isTrue()
+ }
+
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentButNoChipView_returnsFalse() {
+ controller.setChipView(null)
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ assertThat(controller.hasOngoingCall).isFalse()
+ }
+
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentThenRemoved_returnsFalse() {
+ val ongoingCallNotifEntry = createOngoingCallNotifEntry()
+
+ notifCollectionListener.onEntryUpdated(ongoingCallNotifEntry)
+ notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
+
+ assertThat(controller.hasOngoingCall).isFalse()
+ }
+
+ private fun createOngoingCallNotifEntry(): NotificationEntry {
+ val notificationEntryBuilder = NotificationEntryBuilder()
+ notificationEntryBuilder.modifyNotification(context).style = ongoingCallStyle
+ return notificationEntryBuilder.build()
+ }
+
+ private fun createNotCallNotifEntry() = NotificationEntryBuilder().build()
+}
+
+private val ongoingCallStyle = Notification.CallStyle.forOngoingCall(
+ Person.Builder().setName("name").build(),
+ /* hangUpIntent= */ mock(PendingIntent::class.java))
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index ed77147..65a2a7b 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.DUMP;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
@@ -69,6 +70,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.LocationPermissionChecker;
import com.android.server.vcn.TelephonySubscriptionTracker;
import com.android.server.vcn.Vcn;
@@ -76,7 +78,9 @@
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -928,6 +932,33 @@
}
}
+ /**
+ * Dumps the state of the VcnManagementService for logging and debugging purposes.
+ *
+ * <p>PII and credentials MUST NEVER be dumped here.
+ */
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ mContext.enforceCallingOrSelfPermission(DUMP, TAG);
+
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+
+ pw.println("VcnManagementService dump:");
+ pw.increaseIndent();
+
+ mNetworkProvider.dump(pw);
+
+ synchronized (mLock) {
+ pw.println("mVcns:");
+ for (Vcn vcn : mVcns.values()) {
+ vcn.dump(pw);
+ }
+ pw.println();
+ }
+
+ pw.decreaseIndent();
+ }
+
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
/** Callback for Vcn signals sent up to VcnManagementService. */
public interface VcnCallback {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 23dda78..a737ea7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15656,9 +15656,11 @@
final ActivityServiceConnectionsHolder holder =
(ActivityServiceConnectionsHolder) connectionHolder;
synchronized (ActivityManagerService.this) {
- holder.forEachConnection(cr -> mServices.removeConnectionLocked(
- (ConnectionRecord) cr, null /* skipApp */, holder /* skipAct */,
- false /* enqueueOomAdj */));
+ synchronized (mProcLock) {
+ holder.forEachConnection(cr -> mServices.removeConnectionLocked(
+ (ConnectionRecord) cr, null /* skipApp */, holder /* skipAct */,
+ false /* enqueueOomAdj */));
+ }
}
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 2bc81cb..9c10814 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -31,6 +31,7 @@
import android.app.UriGrantsManager;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -57,10 +58,6 @@
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.system.VmSocketAddress;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
@@ -82,128 +79,9 @@
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.WindowManagerInternal;
-import java.io.FileDescriptor;
-import java.io.InterruptedIOException;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
-
-// The following class is Android Emulator specific. It is used to read and
-// write contents of the host system's clipboard.
-class HostClipboardMonitor implements Runnable {
- public interface HostClipboardCallback {
- void onHostClipboardUpdated(String contents);
- }
-
- private FileDescriptor mPipe = null;
- private HostClipboardCallback mHostClipboardCallback;
- private static final String PIPE_NAME = "pipe:clipboard";
- private static final int HOST_PORT = 5000;
-
- private static byte[] createOpenHandshake() {
- // String.getBytes doesn't include the null terminator,
- // but the QEMU pipe device requires the pipe service name
- // to be null-terminated.
-
- final byte[] bits = Arrays.copyOf(PIPE_NAME.getBytes(), PIPE_NAME.length() + 1);
- bits[PIPE_NAME.length()] = 0;
- return bits;
- }
-
- private boolean openPipe() {
- try {
- final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0);
-
- try {
- Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST));
-
- final byte[] handshake = createOpenHandshake();
- Os.write(fd, handshake, 0, handshake.length);
- mPipe = fd;
- return true;
- } catch (ErrnoException | SocketException | InterruptedIOException e) {
- Os.close(fd);
- }
- } catch (ErrnoException e) {
- }
-
- return false;
- }
-
- private void closePipe() {
- try {
- final FileDescriptor fd = mPipe;
- mPipe = null;
- if (fd != null) {
- Os.close(fd);
- }
- } catch (ErrnoException ignore) {
- }
- }
-
- private byte[] receiveMessage() throws ErrnoException, InterruptedIOException {
- final byte[] lengthBits = new byte[4];
- Os.read(mPipe, lengthBits, 0, lengthBits.length);
-
- final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
- bb.order(ByteOrder.LITTLE_ENDIAN);
- final int msgLen = bb.getInt();
-
- final byte[] msg = new byte[msgLen];
- Os.read(mPipe, msg, 0, msg.length);
-
- return msg;
- }
-
- private void sendMessage(byte[] msg) throws ErrnoException, InterruptedIOException {
- final byte[] lengthBits = new byte[4];
- final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
- bb.order(ByteOrder.LITTLE_ENDIAN);
- bb.putInt(msg.length);
-
- Os.write(mPipe, lengthBits, 0, lengthBits.length);
- Os.write(mPipe, msg, 0, msg.length);
- }
-
- public HostClipboardMonitor(HostClipboardCallback cb) {
- mHostClipboardCallback = cb;
- }
-
- @Override
- public void run() {
- while (!Thread.interrupted()) {
- try {
- // There's no guarantee that QEMU pipes will be ready at the moment
- // this method is invoked. We simply try to get the pipe open and
- // retry on failure indefinitely.
- while ((mPipe == null) && !openPipe()) {
- Thread.sleep(100);
- }
-
- final byte[] receivedData = receiveMessage();
- mHostClipboardCallback.onHostClipboardUpdated(
- new String(receivedData));
- } catch (ErrnoException | InterruptedIOException e) {
- closePipe();
- } catch (InterruptedException e) {
- }
- }
- }
-
- public void setHostClipboard(String content) {
- try {
- if (mPipe != null) {
- sendMessage(content.getBytes());
- }
- } catch (ErrnoException | InterruptedIOException e) {
- Slog.e("HostClipboardMonitor",
- "Failed to set host clipboard " + e.getMessage());
- }
- }
-}
+import java.util.function.Consumer;
/**
* Implementation of the clipboard for copy and paste.
@@ -220,8 +98,6 @@
SystemProperties.getBoolean("ro.boot.qemu", false);
// DeviceConfig properties
- private static final String PROPERTY_SHOW_ACCESS_NOTIFICATIONS = "show_access_notifications";
- private static final boolean DEFAULT_SHOW_ACCESS_NOTIFICATIONS = true;
private static final String PROPERTY_MAX_CLASSIFICATION_LENGTH = "max_classification_length";
private static final int DEFAULT_MAX_CLASSIFICATION_LENGTH = 400;
@@ -235,14 +111,15 @@
private final ContentCaptureManagerInternal mContentCaptureInternal;
private final AutofillManagerInternal mAutofillInternal;
private final IBinder mPermissionOwner;
- private final HostClipboardMonitor mHostClipboardMonitor;
+ private final Consumer<ClipData> mEmulatorClipboardMonitor;
private final Handler mWorkerHandler;
@GuardedBy("mLock")
private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
@GuardedBy("mLock")
- private boolean mShowAccessNotifications = DEFAULT_SHOW_ACCESS_NOTIFICATIONS;
+ private boolean mShowAccessNotifications =
+ ClipboardManager.DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS;
@GuardedBy("mLock")
private int mMaxClassificationLength = DEFAULT_MAX_CLASSIFICATION_LENGTH;
@@ -267,24 +144,14 @@
final IBinder permOwner = mUgmInternal.newUriPermissionOwner("clipboard");
mPermissionOwner = permOwner;
if (IS_EMULATOR) {
- mHostClipboardMonitor = new HostClipboardMonitor(
- new HostClipboardMonitor.HostClipboardCallback() {
- @Override
- public void onHostClipboardUpdated(String contents){
- ClipData clip =
- new ClipData("host clipboard",
- new String[]{"text/plain"},
- new ClipData.Item(contents));
- synchronized (mLock) {
- setPrimaryClipInternalLocked(getClipboardLocked(0), clip,
- android.os.Process.SYSTEM_UID, null);
- }
- }
- });
- Thread hostMonitorThread = new Thread(mHostClipboardMonitor);
- hostMonitorThread.start();
+ mEmulatorClipboardMonitor = new EmulatorClipboardMonitor((clip) -> {
+ synchronized (mLock) {
+ setPrimaryClipInternalLocked(getClipboardLocked(0), clip,
+ android.os.Process.SYSTEM_UID, null);
+ }
+ });
} else {
- mHostClipboardMonitor = null;
+ mEmulatorClipboardMonitor = (clip) -> {};
}
updateConfig();
@@ -310,8 +177,10 @@
private void updateConfig() {
synchronized (mLock) {
- mShowAccessNotifications = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CLIPBOARD,
- PROPERTY_SHOW_ACCESS_NOTIFICATIONS, DEFAULT_SHOW_ACCESS_NOTIFICATIONS);
+ mShowAccessNotifications = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CLIPBOARD,
+ ClipboardManager.DEVICE_CONFIG_SHOW_ACCESS_NOTIFICATIONS,
+ ClipboardManager.DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS);
mMaxClassificationLength = DeviceConfig.getInt(DeviceConfig.NAMESPACE_CLIPBOARD,
PROPERTY_MAX_CLASSIFICATION_LENGTH, DEFAULT_MAX_CLASSIFICATION_LENGTH);
}
@@ -643,18 +512,7 @@
@GuardedBy("mLock")
private void setPrimaryClipInternalLocked(
@Nullable ClipData clip, int uid, @Nullable String sourcePackage) {
- // Push clipboard to host, if any
- if (mHostClipboardMonitor != null) {
- if (clip == null) {
- // Someone really wants the clipboard cleared, so push empty
- mHostClipboardMonitor.setHostClipboard("");
- } else if (clip.getItemCount() > 0) {
- final CharSequence text = clip.getItemAt(0).getText();
- if (text != null) {
- mHostClipboardMonitor.setHostClipboard(text.toString());
- }
- }
- }
+ mEmulatorClipboardMonitor.accept(clip);
final int userId = UserHandle.getUserId(uid);
if (clip != null) {
@@ -1056,11 +914,9 @@
if (clipboard.primaryClip == null) {
return;
}
- if (!mShowAccessNotifications) {
- return;
- }
if (Settings.Secure.getInt(getContext().getContentResolver(),
- Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, 1) == 0) {
+ Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS,
+ (mShowAccessNotifications ? 1 : 0)) == 0) {
return;
}
// Don't notify if the app accessing the clipboard is the same as the current owner.
diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
new file mode 100644
index 0000000..62b701a
--- /dev/null
+++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
@@ -0,0 +1,168 @@
+/*
+ * 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.server.clipboard;
+
+import android.annotation.Nullable;
+import android.content.ClipData;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.VmSocketAddress;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+// The following class is Android Emulator specific. It is used to read and
+// write contents of the host system's clipboard.
+class EmulatorClipboardMonitor implements Consumer<ClipData> {
+ private static final String TAG = "EmulatorClipboardMonitor";
+ private static final String PIPE_NAME = "pipe:clipboard";
+ private static final int HOST_PORT = 5000;
+ private final Thread mHostMonitorThread;
+ private FileDescriptor mPipe = null;
+
+ private static byte[] createOpenHandshake() {
+ // String.getBytes doesn't include the null terminator,
+ // but the QEMU pipe device requires the pipe service name
+ // to be null-terminated.
+
+ final byte[] bits = Arrays.copyOf(PIPE_NAME.getBytes(), PIPE_NAME.length() + 1);
+ bits[PIPE_NAME.length()] = 0;
+ return bits;
+ }
+
+ private boolean isPipeOpened() {
+ return mPipe != null;
+ }
+
+ private synchronized boolean openPipe() {
+ if (mPipe != null) {
+ return true;
+ }
+
+ try {
+ final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0);
+
+ try {
+ Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST));
+
+ final byte[] handshake = createOpenHandshake();
+ Os.write(fd, handshake, 0, handshake.length);
+ mPipe = fd;
+ return true;
+ } catch (ErrnoException | SocketException | InterruptedIOException e) {
+ Os.close(fd);
+ }
+ } catch (ErrnoException e) {
+ }
+
+ return false;
+ }
+
+ private synchronized void closePipe() {
+ try {
+ final FileDescriptor fd = mPipe;
+ mPipe = null;
+ if (fd != null) {
+ Os.close(fd);
+ }
+ } catch (ErrnoException ignore) {
+ }
+ }
+
+ private byte[] receiveMessage() throws ErrnoException, InterruptedIOException {
+ final byte[] lengthBits = new byte[4];
+ Os.read(mPipe, lengthBits, 0, lengthBits.length);
+
+ final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ final int msgLen = bb.getInt();
+
+ final byte[] msg = new byte[msgLen];
+ Os.read(mPipe, msg, 0, msg.length);
+
+ return msg;
+ }
+
+ private void sendMessage(final byte[] msg) throws ErrnoException, InterruptedIOException {
+ final byte[] lengthBits = new byte[4];
+ final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ bb.putInt(msg.length);
+
+ Os.write(mPipe, lengthBits, 0, lengthBits.length);
+ Os.write(mPipe, msg, 0, msg.length);
+ }
+
+ EmulatorClipboardMonitor(final Consumer<ClipData> setAndroidClipboard) {
+ this.mHostMonitorThread = new Thread(() -> {
+ while (!Thread.interrupted()) {
+ try {
+ // There's no guarantee that QEMU pipes will be ready at the moment
+ // this method is invoked. We simply try to get the pipe open and
+ // retry on failure indefinitely.
+ while (!openPipe()) {
+ Thread.sleep(100);
+ }
+
+ final byte[] receivedData = receiveMessage();
+
+ final String str = new String(receivedData);
+ final ClipData clip = new ClipData("host clipboard",
+ new String[]{"text/plain"},
+ new ClipData.Item(str));
+
+ setAndroidClipboard.accept(clip);
+ } catch (ErrnoException | InterruptedIOException e) {
+ closePipe();
+ } catch (InterruptedException | IllegalArgumentException e) {
+ }
+ }
+ });
+
+ this.mHostMonitorThread.start();
+ }
+
+ @Override
+ public void accept(final @Nullable ClipData clip) {
+ if (clip == null) {
+ setHostClipboardImpl("");
+ } else if (clip.getItemCount() > 0) {
+ final CharSequence text = clip.getItemAt(0).getText();
+ if (text != null) {
+ setHostClipboardImpl(text.toString());
+ }
+ }
+ }
+
+ private void setHostClipboardImpl(final String value) {
+ try {
+ if (isPipeOpened()) {
+ sendMessage(value.getBytes());
+ }
+ } catch (ErrnoException | InterruptedIOException e) {
+ Slog.e(TAG, "Failed to set host clipboard " + e.getMessage());
+ } catch (IllegalArgumentException e) {
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/clipboard/OWNERS b/services/core/java/com/android/server/clipboard/OWNERS
new file mode 100644
index 0000000..5449df9
--- /dev/null
+++ b/services/core/java/com/android/server/clipboard/OWNERS
@@ -0,0 +1 @@
+per-file EmulatorClipboardMonitor.java = bohu@google.com,lfy@google.com,rkir@google.com
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 03fb3a4..acfeb6c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -713,7 +713,9 @@
assertRunOnServiceThread();
if (!mService.isPowerStandbyOrTransient()) {
addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
- if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+ if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
+ startArcAction(false);
+ } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
&& !hasAction(SetArcTransmissionStateAction.class)) {
startArcAction(true);
}
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index f5d6489..1050835 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -27,6 +27,7 @@
import android.service.notification.IConditionProvider;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
+import android.util.Log;
import android.util.Slog;
import java.io.PrintWriter;
@@ -122,8 +123,11 @@
public static void traceSetNotificationPolicy(String pkg, int targetSdk,
NotificationManager.Policy policy) {
- append(TYPE_SET_NOTIFICATION_POLICY, "pkg=" + pkg + " targetSdk=" + targetSdk
- + " NotificationPolicy=" + policy.toString());
+ String policyLog = "pkg=" + pkg + " targetSdk=" + targetSdk
+ + " NotificationPolicy=" + policy.toString();
+ append(TYPE_SET_NOTIFICATION_POLICY, policyLog);
+ // TODO(b/180205791): remove when we can better surface apps that are changing policy
+ Log.d(TAG, "Zen Policy Changed: " + policyLog);
}
public static void traceSubscribe(Uri uri, IConditionProvider provider, RemoteException e) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a6d4ed9..e532790 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -4157,7 +4157,7 @@
if (stageDir != null && !params.isStaged) {
try {
if (incrementalFileStorages != null) {
- incrementalFileStorages.cleanUp();
+ incrementalFileStorages.cleanUpAndMarkComplete();
}
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
@@ -4183,7 +4183,7 @@
}
try {
if (incrementalFileStorages != null) {
- incrementalFileStorages.cleanUp();
+ incrementalFileStorages.cleanUpAndMarkComplete();
}
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 30ce57f..9477464 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5966,7 +5966,8 @@
backgroundHandler,
SYSTEM_PARTITIONS,
(i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
- (i, pm) -> PermissionManagerService.create(context),
+ (i, pm) -> PermissionManagerService.create(context,
+ i.getSystemConfig().getAvailableFeatures()),
(i, pm) -> new UserManagerService(context, pm,
new UserDataPreparer(installer, installLock, context, onlyCore),
lock),
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 310ef23..2d1178a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -69,8 +69,10 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PermissionGroupInfoFlags;
import android.content.pm.PackageManager.PermissionInfoFlags;
@@ -85,7 +87,6 @@
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.metrics.LogMaker;
import android.os.AsyncTask;
-import android.content.AttributionSource;
import android.os.Binder;
import android.os.Build;
import android.os.Debug;
@@ -177,6 +178,10 @@
private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
+ // For automotive products, CarService enforces allow-listing of the privileged permissions
+ // com.android.car is the package name which declares auto specific permissions
+ private static final String CAR_PACKAGE_NAME = "com.android.car";
+
/** Cap the size of permission trees that 3rd party apps can define; in characters of text */
private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768;
/** Empty array to avoid allocations */
@@ -210,6 +215,10 @@
STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
}
+ /** Set of source package names for Privileged Permission Allowlist */
+ private final ArraySet<String> mPrivilegedPermissionAllowlistSourcePackageNames =
+ new ArraySet<>();
+
/** Lock to protect internal data access */
private final Object mLock = new Object();
@@ -356,7 +365,8 @@
}
};
- PermissionManagerService(@NonNull Context context) {
+ PermissionManagerService(@NonNull Context context,
+ @NonNull ArrayMap<String, FeatureInfo> availableFeatures) {
// The package info cache is the cache for package and permission information.
// Disable the package info and package permission caches locally but leave the
// checkPermission cache active.
@@ -368,6 +378,13 @@
mUserManagerInt = LocalServices.getService(UserManagerInternal.class);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mPrivilegedPermissionAllowlistSourcePackageNames.add(PLATFORM_PACKAGE_NAME);
+ // PackageManager.hasSystemFeature() is not used here because PackageManagerService
+ // isn't ready yet.
+ if (availableFeatures.containsKey(PackageManager.FEATURE_AUTOMOTIVE)) {
+ mPrivilegedPermissionAllowlistSourcePackageNames.add(CAR_PACKAGE_NAME);
+ }
+
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
@@ -422,7 +439,8 @@
* lock created by the permission manager itself.
*/
@NonNull
- public static PermissionManagerServiceInternal create(@NonNull Context context) {
+ public static PermissionManagerServiceInternal create(@NonNull Context context,
+ ArrayMap<String, FeatureInfo> availableFeatures) {
final PermissionManagerServiceInternal permMgrInt =
LocalServices.getService(PermissionManagerServiceInternal.class);
if (permMgrInt != null) {
@@ -431,7 +449,7 @@
PermissionManagerService permissionService =
(PermissionManagerService) ServiceManager.getService("permissionmgr");
if (permissionService == null) {
- permissionService = new PermissionManagerService(context);
+ permissionService = new PermissionManagerService(context, availableFeatures);
ServiceManager.addService("permissionmgr", permissionService);
}
return LocalServices.getService(PermissionManagerServiceInternal.class);
@@ -3318,7 +3336,8 @@
if (!pkg.isPrivileged()) {
return true;
}
- if (!Objects.equals(permission.getPackageName(), PLATFORM_PACKAGE_NAME)) {
+ if (!mPrivilegedPermissionAllowlistSourcePackageNames
+ .contains(permission.getPackageName())) {
return true;
}
final String permissionName = permission.getName();
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index fa27b4b4..25709d4 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -21,11 +21,22 @@
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
import android.app.SyncNotedAppOp;
+import android.app.role.RoleManager;
import android.content.AttributionSource;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.location.LocationManagerInternal;
+import android.net.Uri;
import android.os.IBinder;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.HeptFunction;
@@ -35,6 +46,8 @@
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -42,9 +55,21 @@
* This class defines policy for special behaviors around app ops.
*/
public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegate {
+ private static final String LOG_TAG = AppOpsPolicy.class.getName();
+
+ private static final String ACTIVITY_RECOGNITION_TAGS =
+ "android:activity_recognition_allow_listed_tags";
+ private static final String ACTIVITY_RECOGNITION_TAGS_SEPARATOR = ";";
+
@NonNull
private final Object mLock = new Object();
+ @NonNull
+ private final Context mContext;
+
+ @NonNull
+ private final RoleManager mRoleManager;
+
/**
* The locking policy around the location tags is a bit special. Since we want to
* avoid grabbing the lock on every op note we are taking the approach where the
@@ -60,48 +85,57 @@
private final ConcurrentHashMap<Integer, ArrayMap<String, ArraySet<String>>> mLocationTags =
new ConcurrentHashMap<>();
- public AppOpsPolicy() {
+ @GuardedBy("mLock - writes only - see above")
+ @NonNull
+ private final ConcurrentHashMap<Integer, ArrayMap<String, ArraySet<String>>>
+ mActivityRecognitionTags = new ConcurrentHashMap<>();
+
+ public AppOpsPolicy(@NonNull Context context) {
+ mContext = context;
+ mRoleManager = mContext.getSystemService(RoleManager.class);
+
final LocationManagerInternal locationManagerInternal = LocalServices.getService(
LocationManagerInternal.class);
locationManagerInternal.setOnProviderLocationTagsChangeListener((providerTagInfo) -> {
synchronized (mLock) {
- final int uid = providerTagInfo.getUid();
- // We make a copy of the per UID state to limit our mutation to one
- // operation in the underlying concurrent data structure.
- ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
- if (uidTags != null) {
- uidTags = new ArrayMap<>(uidTags);
- }
-
- final String packageName = providerTagInfo.getPackageName();
- ArraySet<String> packageTags = (uidTags != null) ? uidTags.get(packageName) : null;
- if (packageTags != null) {
- packageTags = new ArraySet<>(packageTags);
- }
-
- final Set<String> providerTags = providerTagInfo.getTags();
- if (providerTags != null && !providerTags.isEmpty()) {
- if (packageTags != null) {
- packageTags.clear();
- packageTags.addAll(providerTags);
- } else {
- packageTags = new ArraySet<>(providerTags);
- }
- if (uidTags == null) {
- uidTags = new ArrayMap<>();
- }
- uidTags.put(packageName, packageTags);
- mLocationTags.put(uid, uidTags);
- } else if (uidTags != null) {
- uidTags.remove(packageName);
- if (!uidTags.isEmpty()) {
- mLocationTags.put(uid, uidTags);
- } else {
- mLocationTags.remove(uid);
- }
- }
+ updateAllowListedTagsForPackageLocked(providerTagInfo.getUid(),
+ providerTagInfo.getPackageName(), providerTagInfo.getTags(),
+ mLocationTags);
}
});
+
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ intentFilter.addDataScheme("package");
+
+ context.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
+ final String packageName = uri.getSchemeSpecificPart();
+ if (TextUtils.isEmpty(packageName)) {
+ return;
+ }
+ final List<String> activityRecognizers = mRoleManager.getRoleHolders(
+ RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER);
+ if (activityRecognizers.contains(packageName)) {
+ updateActivityRecognizerTags(packageName);
+ }
+ }
+ }, UserHandle.SYSTEM, intentFilter, null, null);
+
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(context.getMainExecutor(),
+ (String roleName, UserHandle user) -> {
+ if (RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER.equals(roleName)) {
+ initializeActivityRecognizersTags();
+ }
+ }, UserHandle.SYSTEM);
+
+ initializeActivityRecognizersTags();
}
@Override
@@ -121,7 +155,7 @@
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable
String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer,
String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
- return superImpl.apply(resolveOpCode(code, uid, packageName, attributionTag), uid,
+ return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), uid,
packageName, attributionTag, shouldCollectAsyncNotedOp,
message, shouldCollectMessage);
}
@@ -132,7 +166,7 @@
boolean shouldCollectMessage, boolean skipProxyOperation, @NonNull HexFunction<Integer,
AttributionSource, Boolean, String, Boolean, Boolean,
SyncNotedAppOp> superImpl) {
- return superImpl.apply(resolveOpCode(code, attributionSource.getUid(),
+ return superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(),
attributionSource.getPackageName(), attributionSource.getAttributionTag()),
attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
skipProxyOperation);
@@ -144,7 +178,7 @@
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
boolean skipProxyOperation, @NonNull OctFunction<IBinder, Integer, AttributionSource,
Boolean, Boolean, String, Boolean, Boolean, SyncNotedAppOp> superImpl) {
- return superImpl.apply(token, resolveOpCode(code, attributionSource.getUid(),
+ return superImpl.apply(token, resolveDatasourceOp(code, attributionSource.getUid(),
attributionSource.getPackageName(), attributionSource.getAttributionTag()),
attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message,
shouldCollectMessage, skipProxyOperation);
@@ -154,36 +188,129 @@
public void finishProxyOperation(IBinder clientId, int code,
@NonNull AttributionSource attributionSource,
@NonNull TriFunction<IBinder, Integer, AttributionSource, Void> superImpl) {
- superImpl.apply(clientId, resolveOpCode(code, attributionSource.getUid(),
+ superImpl.apply(clientId, resolveDatasourceOp(code, attributionSource.getUid(),
attributionSource.getPackageName(), attributionSource.getAttributionTag()),
attributionSource);
}
- private int resolveOpCode(int code, int uid, @NonNull String packageName,
+ private int resolveDatasourceOp(int code, int uid, @NonNull String packageName,
@Nullable String attributionTag) {
- if (isHandledOp(code) && attributionTag != null) {
- // Only a single lookup from the underlying concurrent data structure
- final ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
- if (uidTags != null) {
- final ArraySet<String> packageTags = uidTags.get(packageName);
- if (packageTags != null && packageTags.contains(attributionTag)) {
- return resolveHandledOp(code);
+ if (attributionTag == null) {
+ return code;
+ }
+ int resolvedCode = resolveLocationOp(code);
+ if (resolvedCode != code) {
+ if (isDatasourceAttributionTag(uid, packageName, attributionTag,
+ mLocationTags)) {
+ return resolvedCode;
+ }
+ } else {
+ resolvedCode = resolveArOp(code);
+ if (resolvedCode != code) {
+ if (isDatasourceAttributionTag(uid, packageName, attributionTag,
+ mActivityRecognitionTags)) {
+ return resolvedCode;
}
}
}
return code;
}
- private static boolean isHandledOp(int code) {
- switch (code) {
- case AppOpsManager.OP_FINE_LOCATION:
- case AppOpsManager.OP_COARSE_LOCATION:
+ private void initializeActivityRecognizersTags() {
+ final List<String> activityRecognizers = mRoleManager.getRoleHolders(
+ RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER);
+ final int recognizerCount = activityRecognizers.size();
+ if (recognizerCount > 0) {
+ for (int i = 0; i < recognizerCount; i++) {
+ final String activityRecognizer = activityRecognizers.get(i);
+ updateActivityRecognizerTags(activityRecognizer);
+ }
+ } else {
+ clearActivityRecognitionTags();
+ }
+ }
+
+ private void clearActivityRecognitionTags() {
+ synchronized (mLock) {
+ mActivityRecognitionTags.clear();
+ }
+ }
+
+ private void updateActivityRecognizerTags(@NonNull String activityRecognizer) {
+ try {
+ final ApplicationInfo recognizerAppInfo = mContext.getPackageManager()
+ .getApplicationInfoAsUser(activityRecognizer, PackageManager.GET_META_DATA,
+ UserHandle.USER_SYSTEM);
+ if (recognizerAppInfo.metaData == null) {
+ return;
+ }
+ final String tagsList = recognizerAppInfo.metaData.getString(ACTIVITY_RECOGNITION_TAGS);
+ if (tagsList != null) {
+ final String[] tags = tagsList.split(ACTIVITY_RECOGNITION_TAGS_SEPARATOR);
+ synchronized (mLock) {
+ updateAllowListedTagsForPackageLocked(recognizerAppInfo.uid,
+ recognizerAppInfo.packageName, new ArraySet<>(tags),
+ mActivityRecognitionTags);
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.wtf(LOG_TAG, "Missing " + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER
+ + " role holder package " + activityRecognizer);
+ }
+ }
+
+ private static void updateAllowListedTagsForPackageLocked(int uid, String packageName,
+ Set<String> allowListedTags, ConcurrentHashMap<Integer, ArrayMap<String,
+ ArraySet<String>>> datastore) {
+ // We make a copy of the per UID state to limit our mutation to one
+ // operation in the underlying concurrent data structure.
+ ArrayMap<String, ArraySet<String>> uidTags = datastore.get(uid);
+ if (uidTags != null) {
+ uidTags = new ArrayMap<>(uidTags);
+ }
+
+ ArraySet<String> packageTags = (uidTags != null) ? uidTags.get(packageName) : null;
+ if (packageTags != null) {
+ packageTags = new ArraySet<>(packageTags);
+ }
+
+ if (allowListedTags != null && !allowListedTags.isEmpty()) {
+ if (packageTags != null) {
+ packageTags.clear();
+ packageTags.addAll(allowListedTags);
+ } else {
+ packageTags = new ArraySet<>(allowListedTags);
+ }
+ if (uidTags == null) {
+ uidTags = new ArrayMap<>();
+ }
+ uidTags.put(packageName, packageTags);
+ datastore.put(uid, uidTags);
+ } else if (uidTags != null) {
+ uidTags.remove(packageName);
+ if (!uidTags.isEmpty()) {
+ datastore.put(uid, uidTags);
+ } else {
+ datastore.remove(uid);
+ }
+ }
+ }
+
+ private static boolean isDatasourceAttributionTag(int uid, @NonNull String packageName,
+ @NonNull String attributionTag, @NonNull Map<Integer, ArrayMap<String,
+ ArraySet<String>>> mappedOps) {
+ // Only a single lookup from the underlying concurrent data structure
+ final ArrayMap<String, ArraySet<String>> uidTags = mappedOps.get(uid);
+ if (uidTags != null) {
+ final ArraySet<String> packageTags = uidTags.get(packageName);
+ if (packageTags != null && packageTags.contains(attributionTag)) {
return true;
+ }
}
return false;
}
- private static int resolveHandledOp(int code) {
+ private static int resolveLocationOp(int code) {
switch (code) {
case AppOpsManager.OP_FINE_LOCATION:
return AppOpsManager.OP_FINE_LOCATION_SOURCE;
@@ -192,4 +319,11 @@
}
return code;
}
+
+ private static int resolveArOp(int code) {
+ if (code == AppOpsManager.OP_ACTIVITY_RECOGNITION) {
+ return AppOpsManager.OP_ACTIVITY_RECOGNITION_SOURCE;
+ }
+ return code;
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
index 52ff48b..d91e9c2 100644
--- a/services/core/java/com/android/server/timedetector/ServerFlags.java
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -28,6 +28,8 @@
import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ServiceConfigAccessor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.Map;
import java.util.Objects;
@@ -53,14 +55,15 @@
*/
@StringDef(prefix = "KEY_", value = {
KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
- KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
- KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
})
+ @Retention(RetentionPolicy.SOURCE)
@interface DeviceConfigKey {}
/**
@@ -75,19 +78,19 @@
/**
* The key for the server flag that can override the device config for whether the primary
- * location time zone provider is enabled or disabled.
+ * location time zone provider is enabled, disabled, or (for testing) in simulation mode.
*/
@DeviceConfigKey
- public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
- "primary_location_time_zone_provider_enabled_override";
+ public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ "primary_location_time_zone_provider_mode_override";
/**
* The key for the server flag that can override the device config for whether the secondary
- * location time zone provider is enabled or disabled.
+ * location time zone provider is enabled or disabled, or (for testing) in simulation mode.
*/
@DeviceConfigKey
- public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
- "secondary_location_time_zone_provider_enabled_override";
+ public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ "secondary_location_time_zone_provider_mode_override";
/**
* The key for the minimum delay after location time zone detection has been enabled before the
@@ -196,6 +199,16 @@
}
/**
+ * Returns an optional string value from {@link DeviceConfig} from the system_time
+ * namespace, returns {@link Optional#empty()} if there is no explicit value set.
+ */
+ @NonNull
+ public Optional<String> getOptionalString(@DeviceConfigKey String key) {
+ String value = DeviceConfig.getProperty(NAMESPACE_SYSTEM_TIME, key);
+ return Optional.ofNullable(value);
+ }
+
+ /**
* Returns an optional boolean value from {@link DeviceConfig} from the system_time
* namespace, returns {@link Optional#empty()} if there is no explicit value set.
*/
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 222e852..50d37f4 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -17,6 +17,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -27,6 +28,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.server.timedetector.ServerFlags;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.time.Duration;
import java.util.Collections;
import java.util.Objects;
@@ -40,13 +45,38 @@
*/
public final class ServiceConfigAccessor {
+ @StringDef(prefix = "PROVIDER_MODE_",
+ value = { PROVIDER_MODE_SIMULATED, PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED})
+ @Retention(RetentionPolicy.SOURCE)
+ @Target(ElementType.TYPE_USE)
+ @interface ProviderMode {}
+
+ /**
+ * The "simulated" provider mode.
+ * For use with {@link #getPrimaryLocationTimeZoneProviderMode()} and {@link
+ * #getSecondaryLocationTimeZoneProviderMode()}.
+ */
+ public static final @ProviderMode String PROVIDER_MODE_SIMULATED = "simulated";
+
+ /**
+ * The "disabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()}
+ * and {@link #getSecondaryLocationTimeZoneProviderMode()}.
+ */
+ public static final @ProviderMode String PROVIDER_MODE_DISABLED = "disabled";
+
+ /**
+ * The "enabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()}
+ * and {@link #getSecondaryLocationTimeZoneProviderMode()}.
+ */
+ public static final @ProviderMode String PROVIDER_MODE_ENABLED = "enabled";
+
private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
new ArraySet<>(new String[] {
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
- ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
- ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS
@@ -139,14 +169,28 @@
/**
* Returns {@code true} if the location-based time zone detection feature is supported on the
- * device. This can be used during feature testing on builds that are capable of location time
- * zone detection to enable / disable the feature for some users.
+ * device.
*/
public boolean isGeoTimeZoneDetectionFeatureSupported() {
+ // For the feature to be enabled it must:
+ // 1) Be turned on in config.
+ // 2) Not be turned off via a server flag.
+ // 3) There must be at least one location time zone provider enabled / configured.
return mGeoDetectionFeatureSupportedInConfig
- && isGeoTimeZoneDetectionFeatureSupportedInternal();
+ && isGeoTimeZoneDetectionFeatureSupportedInternal()
+ && atLeastOneProviderIsEnabled();
}
+ private boolean atLeastOneProviderIsEnabled() {
+ return !(Objects.equals(getPrimaryLocationTimeZoneProviderMode(), PROVIDER_MODE_DISABLED)
+ && Objects.equals(getSecondaryLocationTimeZoneProviderMode(),
+ PROVIDER_MODE_DISABLED));
+ }
+
+ /**
+ * Returns {@code true} if the location-based time zone detection feature is not explicitly
+ * disabled by a server flag.
+ */
private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() {
final boolean defaultEnabled = true;
return mServerFlags.getBoolean(
@@ -154,42 +198,49 @@
defaultEnabled);
}
+ @NonNull
+ public String getPrimaryLocationTimeZoneProviderPackageName() {
+ return mContext.getResources().getString(
+ R.string.config_primaryLocationTimeZoneProviderPackageName);
+ }
+
+ @NonNull
+ public String getSecondaryLocationTimeZoneProviderPackageName() {
+ return mContext.getResources().getString(
+ R.string.config_secondaryLocationTimeZoneProviderPackageName);
+ }
+
/**
* Returns {@code true} if the primary location time zone provider can be used.
*/
- public boolean isPrimaryLocationTimeZoneProviderEnabled() {
- return getPrimaryLocationTimeZoneProviderEnabledOverride()
- .orElse(isPrimaryLocationTimeZoneProviderEnabledInConfig());
- }
-
- private boolean isPrimaryLocationTimeZoneProviderEnabledInConfig() {
- int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
- return getConfigBoolean(providerEnabledConfigId);
+ @NonNull
+ public @ProviderMode String getPrimaryLocationTimeZoneProviderMode() {
+ return mServerFlags.getOptionalString(
+ ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE)
+ .orElse(getPrimaryLocationTimeZoneProviderModeFromConfig());
}
@NonNull
- private Optional<Boolean> getPrimaryLocationTimeZoneProviderEnabledOverride() {
- return mServerFlags.getOptionalBoolean(
- ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+ private @ProviderMode String getPrimaryLocationTimeZoneProviderModeFromConfig() {
+ int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
+ return getConfigBoolean(providerEnabledConfigId)
+ ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
}
/**
- * Returns {@code true} if the secondary location time zone provider can be used.
+ * Returns the mode for the secondary location time zone provider can be used.
*/
- public boolean isSecondaryLocationTimeZoneProviderEnabled() {
- return getSecondaryLocationTimeZoneProviderEnabledOverride()
- .orElse(isSecondaryLocationTimeZoneProviderEnabledInConfig());
- }
-
- private boolean isSecondaryLocationTimeZoneProviderEnabledInConfig() {
- int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
- return getConfigBoolean(providerEnabledConfigId);
+ public @ProviderMode String getSecondaryLocationTimeZoneProviderMode() {
+ return mServerFlags.getOptionalString(
+ ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE)
+ .orElse(getSecondaryLocationTimeZoneProviderModeFromConfig());
}
@NonNull
- private Optional<Boolean> getSecondaryLocationTimeZoneProviderEnabledOverride() {
- return mServerFlags.getOptionalBoolean(
- ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+ private @ProviderMode String getSecondaryLocationTimeZoneProviderModeFromConfig() {
+ int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
+ return getConfigBoolean(providerEnabledConfigId)
+ ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
}
/**
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
index fb2a184..d2190fd 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
@@ -30,6 +30,7 @@
import static com.android.server.timezonedetector.location.TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN;
import android.annotation.DurationMillisLong;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteCallback;
@@ -604,14 +605,14 @@
* known provider, then the command is logged and discarded.
*/
void handleProviderTestCommand(
- @NonNull String providerName, @NonNull TestCommand testCommand,
+ @IntRange(from = 0, to = 1) int providerIndex, @NonNull TestCommand testCommand,
@Nullable RemoteCallback callback) {
mThreadingDomain.assertCurrentThread();
- LocationTimeZoneProvider targetProvider = getLocationTimeZoneProvider(providerName);
+ LocationTimeZoneProvider targetProvider = getLocationTimeZoneProvider(providerIndex);
if (targetProvider == null) {
warnLog("Unable to process test command:"
- + " providerName=" + providerName + ", testCommand=" + testCommand);
+ + " providerIndex=" + providerIndex + ", testCommand=" + testCommand);
return;
}
@@ -620,7 +621,7 @@
targetProvider.handleTestCommand(testCommand, callback);
} catch (Exception e) {
warnLog("Unable to process test command:"
- + " providerName=" + providerName + ", testCommand=" + testCommand, e);
+ + " providerIndex=" + providerIndex + ", testCommand=" + testCommand, e);
}
}
}
@@ -658,14 +659,15 @@
}
@Nullable
- private LocationTimeZoneProvider getLocationTimeZoneProvider(@NonNull String providerName) {
+ private LocationTimeZoneProvider getLocationTimeZoneProvider(
+ @IntRange(from = 0, to = 1) int providerIndex) {
LocationTimeZoneProvider targetProvider;
- if (Objects.equals(mPrimaryProvider.getName(), providerName)) {
+ if (providerIndex == 0) {
targetProvider = mPrimaryProvider;
- } else if (Objects.equals(mSecondaryProvider.getName(), providerName)) {
+ } else if (providerIndex == 1) {
targetProvider = mSecondaryProvider;
} else {
- warnLog("Bad providerName=" + providerName);
+ warnLog("Bad providerIndex=" + providerIndex);
targetProvider = null;
}
return targetProvider;
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index 326cfe7..d8d44d4 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -16,13 +16,12 @@
package com.android.server.timezonedetector.location;
-import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
-import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED;
+
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -37,12 +36,12 @@
import android.util.Log;
import android.util.Slog;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.SystemService;
+import com.android.server.timezonedetector.Dumpable;
import com.android.server.timezonedetector.ServiceConfigAccessor;
import com.android.server.timezonedetector.TimeZoneDetectorInternal;
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
@@ -131,11 +130,15 @@
private static final String ATTRIBUTION_TAG = "LocationTimeZoneService";
- private static final String PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
- TimeZoneProviderService.PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE;
- private static final String SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
- TimeZoneProviderService.SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE;
+ @GuardedBy("mSharedLock")
+ private final ProviderConfig mPrimaryProviderConfig = new ProviderConfig(
+ 0 /* index */, "primary",
+ TimeZoneProviderService.PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE);
+ @GuardedBy("mSharedLock")
+ private final ProviderConfig mSecondaryProviderConfig = new ProviderConfig(
+ 1 /* index */, "secondary",
+ TimeZoneProviderService.SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE);
@NonNull private final Context mContext;
@@ -165,14 +168,6 @@
@GuardedBy("mSharedLock")
private ControllerEnvironmentImpl mEnvironment;
- @GuardedBy("mSharedLock")
- @NonNull
- private String mPrimaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE;
-
- @GuardedBy("mSharedLock")
- @NonNull
- private String mSecondaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE;
-
LocationTimeZoneManagerService(Context context) {
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = FgThread.getHandler();
@@ -200,9 +195,14 @@
mThreadingDomain.assertCurrentThread();
synchronized (mSharedLock) {
- // Stop and start the service, waiting until completion.
- stopOnDomainThread();
- startOnDomainThread();
+ // Avoid starting the service if it is currently stopped. This is required because
+ // server flags are used by tests to set behavior with the service stopped, and we don't
+ // want the service being restarted after each flag is set.
+ if (mLocationTimeZoneDetectorController != null) {
+ // Stop and start the service, waiting until completion.
+ stopOnDomainThread();
+ startOnDomainThread();
+ }
}
}
@@ -257,8 +257,8 @@
}
if (mLocationTimeZoneDetectorController == null) {
- LocationTimeZoneProvider primary = createPrimaryProvider();
- LocationTimeZoneProvider secondary = createSecondaryProvider();
+ LocationTimeZoneProvider primary = mPrimaryProviderConfig.createProvider();
+ LocationTimeZoneProvider secondary = mSecondaryProviderConfig.createProvider();
ControllerImpl controller =
new ControllerImpl(mThreadingDomain, primary, secondary);
@@ -273,88 +273,6 @@
}
}
- @NonNull
- private LocationTimeZoneProvider createPrimaryProvider() {
- LocationTimeZoneProviderProxy proxy;
- if (isProviderInSimulationMode(PRIMARY_PROVIDER_NAME)) {
- proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (!isProviderEnabled(PRIMARY_PROVIDER_NAME)) {
- proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else {
- proxy = new RealLocationTimeZoneProviderProxy(
- mContext,
- mHandler,
- mThreadingDomain,
- PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
- R.bool.config_enablePrimaryLocationTimeZoneOverlay,
- R.string.config_primaryLocationTimeZoneProviderPackageName
- );
- }
- ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(0);
- return new BinderLocationTimeZoneProvider(
- providerMetricsLogger, mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
- }
-
- @NonNull
- private LocationTimeZoneProvider createSecondaryProvider() {
- LocationTimeZoneProviderProxy proxy;
- if (isProviderInSimulationMode(SECONDARY_PROVIDER_NAME)) {
- proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (!isProviderEnabled(SECONDARY_PROVIDER_NAME)) {
- proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else {
- proxy = new RealLocationTimeZoneProviderProxy(
- mContext,
- mHandler,
- mThreadingDomain,
- SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
- R.bool.config_enableSecondaryLocationTimeZoneOverlay,
- R.string.config_secondaryLocationTimeZoneProviderPackageName
- );
- }
- ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(1);
- return new BinderLocationTimeZoneProvider(
- providerMetricsLogger, mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
- }
-
- /** Used for bug triage and in tests to simulate provider events. */
- private boolean isProviderInSimulationMode(@NonNull String providerName) {
- return isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_SIMULATED);
- }
-
- /** Used for bug triage, and by tests and experiments to remove a provider. */
- private boolean isProviderEnabled(@NonNull String providerName) {
- if (isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED)) {
- return false;
- }
-
- switch (providerName) {
- case PRIMARY_PROVIDER_NAME: {
- return mServiceConfigAccessor.isPrimaryLocationTimeZoneProviderEnabled();
- }
- case SECONDARY_PROVIDER_NAME: {
- return mServiceConfigAccessor.isSecondaryLocationTimeZoneProviderEnabled();
- }
- default: {
- throw new IllegalArgumentException(providerName);
- }
- }
- }
-
- private boolean isProviderModeOverrideSet(@NonNull String providerName, @NonNull String mode) {
- switch (providerName) {
- case PRIMARY_PROVIDER_NAME: {
- return Objects.equals(mPrimaryProviderModeOverride, mode);
- }
- case SECONDARY_PROVIDER_NAME: {
- return Objects.equals(mSecondaryProviderModeOverride, mode);
- }
- default: {
- throw new IllegalArgumentException(providerName);
- }
- }
- }
-
/**
* Stops the service for tests and other rare cases. To avoid tests needing to sleep, this
* method will not return until all the system server components have stopped.
@@ -390,33 +308,6 @@
}
/** Sets this service into provider state recording mode for tests. */
- void setProviderModeOverride(@NonNull String providerName, @NonNull String mode) {
- enforceManageTimeZoneDetectorPermission();
-
- Preconditions.checkArgument(
- PRIMARY_PROVIDER_NAME.equals(providerName)
- || SECONDARY_PROVIDER_NAME.equals(providerName));
- Preconditions.checkArgument(PROVIDER_MODE_OVERRIDE_DISABLED.equals(mode)
- || PROVIDER_MODE_OVERRIDE_SIMULATED.equals(mode)
- || PROVIDER_MODE_OVERRIDE_NONE.equals(mode));
-
- mThreadingDomain.postAndWait(() -> {
- synchronized (mSharedLock) {
- switch (providerName) {
- case PRIMARY_PROVIDER_NAME: {
- mPrimaryProviderModeOverride = mode;
- break;
- }
- case SECONDARY_PROVIDER_NAME: {
- mSecondaryProviderModeOverride = mode;
- break;
- }
- }
- }
- }, BLOCKING_OP_WAIT_DURATION_MILLIS);
- }
-
- /** Sets this service into provider state recording mode for tests. */
void setProviderStateRecordingEnabled(boolean enabled) {
enforceManageTimeZoneDetectorPermission();
@@ -457,8 +348,8 @@
* Passes a {@link TestCommand} to the specified provider and waits for the response.
*/
@NonNull
- Bundle handleProviderTestCommand(
- @NonNull String providerName, @NonNull TestCommand testCommand) {
+ Bundle handleProviderTestCommand(@IntRange(from = 0, to = 1) int providerIndex,
+ @NonNull TestCommand testCommand) {
enforceManageTimeZoneDetectorPermission();
// Because this method blocks and posts work to the threading domain thread, it would cause
@@ -479,7 +370,7 @@
return;
}
mLocationTimeZoneDetectorController.handleProviderTestCommand(
- providerName, testCommand, remoteCallback);
+ providerIndex, testCommand, remoteCallback);
}
});
@@ -505,6 +396,17 @@
synchronized (mSharedLock) {
ipw.println("LocationTimeZoneManagerService:");
ipw.increaseIndent();
+
+ ipw.println("Primary provider config:");
+ ipw.increaseIndent();
+ mPrimaryProviderConfig.dump(ipw, args);
+ ipw.decreaseIndent();
+
+ ipw.println("Secondary provider config:");
+ ipw.increaseIndent();
+ mSecondaryProviderConfig.dump(ipw, args);
+ ipw.decreaseIndent();
+
if (mLocationTimeZoneDetectorController == null) {
ipw.println("{Stopped}");
} else {
@@ -541,4 +443,75 @@
android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION,
"manage time and time zone detection");
}
+
+ /** An inner class for managing a provider's config. */
+ private final class ProviderConfig implements Dumpable {
+ @IntRange(from = 0, to = 1) private final int mIndex;
+ @NonNull private final String mName;
+ @NonNull private final String mServiceAction;
+
+ ProviderConfig(@IntRange(from = 0, to = 1) int index, @NonNull String name,
+ @NonNull String serviceAction) {
+ Preconditions.checkArgument(index >= 0 && index <= 1);
+ mIndex = index;
+ mName = Objects.requireNonNull(name);
+ mServiceAction = Objects.requireNonNull(serviceAction);
+ }
+
+ @NonNull
+ LocationTimeZoneProvider createProvider() {
+ LocationTimeZoneProviderProxy proxy = createProxy();
+ ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(mIndex);
+ return new BinderLocationTimeZoneProvider(
+ providerMetricsLogger, mThreadingDomain, mName, proxy);
+ }
+
+ @GuardedBy("mSharedLock")
+ @Override
+ public void dump(IndentingPrintWriter ipw, String[] args) {
+ ipw.printf("getMode()=%s\n", getMode());
+ ipw.printf("getPackageName()=%s\n", getPackageName());
+ }
+
+ @NonNull
+ private LocationTimeZoneProviderProxy createProxy() {
+ String mode = getMode();
+ if (Objects.equals(mode, PROVIDER_MODE_SIMULATED)) {
+ return new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
+ } else if (Objects.equals(mode, PROVIDER_MODE_DISABLED)) {
+ return new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
+ } else {
+ // mode == PROVIDER_MODE_OVERRIDE_ENABLED (or unknown).
+ return createRealProxy();
+ }
+ }
+
+ /** Returns the mode of the provider. */
+ @NonNull
+ private String getMode() {
+ if (mIndex == 0) {
+ return mServiceConfigAccessor.getPrimaryLocationTimeZoneProviderMode();
+ } else {
+ return mServiceConfigAccessor.getSecondaryLocationTimeZoneProviderMode();
+ }
+ }
+
+ @NonNull
+ private RealLocationTimeZoneProviderProxy createRealProxy() {
+ String providerServiceAction = mServiceAction;
+ String providerPackageName = getPackageName();
+ return new RealLocationTimeZoneProviderProxy(
+ mContext, mHandler, mThreadingDomain, providerServiceAction,
+ providerPackageName);
+ }
+
+ @NonNull
+ private String getPackageName() {
+ if (mIndex == 0) {
+ return mServiceConfigAccessor.getPrimaryLocationTimeZoneProviderPackageName();
+ } else {
+ return mServiceConfigAccessor.getSecondaryLocationTimeZoneProviderPackageName();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
index 40638080..c6df624 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
@@ -16,19 +16,25 @@
package com.android.server.timezonedetector.location;
import static android.app.time.LocationTimeZoneManager.DUMP_STATE_OPTION_PROTO;
-import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
-import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND;
-import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_START;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_STOP;
+import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS;
+import static com.android.server.timedetector.ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE;
+import static com.android.server.timedetector.ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_ENABLED;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
@@ -53,16 +59,12 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/** Implements the shell command interface for {@link LocationTimeZoneManagerService}. */
class LocationTimeZoneManagerShellCommand extends ShellCommand {
- private static final List<String> VALID_PROVIDER_NAMES =
- Arrays.asList(PRIMARY_PROVIDER_NAME, SECONDARY_PROVIDER_NAME);
-
private final LocationTimeZoneManagerService mService;
LocationTimeZoneManagerShellCommand(LocationTimeZoneManagerService service) {
@@ -82,9 +84,6 @@
case SHELL_COMMAND_STOP: {
return runStop();
}
- case SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE: {
- return runSetProviderModeOverride();
- }
case SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND: {
return runSendProviderTestCommand();
}
@@ -110,10 +109,6 @@
pw.println(" Starts the location_time_zone_manager, creating time zone providers.");
pw.printf(" %s\n", SHELL_COMMAND_STOP);
pw.println(" Stops the location_time_zone_manager, destroying time zone providers.");
- pw.printf(" %s <provider name> <mode>\n", SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE);
- pw.println(" Sets a provider into a test mode next time the service started.");
- pw.printf(" Values: %s|%s|%s\n", PROVIDER_MODE_OVERRIDE_NONE,
- PROVIDER_MODE_OVERRIDE_DISABLED, PROVIDER_MODE_OVERRIDE_SIMULATED);
pw.printf(" %s (true|false)\n", SHELL_COMMAND_RECORD_PROVIDER_STATES);
pw.printf(" Enables / disables provider state recording mode. See also %s. The default"
+ " state is always \"false\".\n", SHELL_COMMAND_DUMP_STATE);
@@ -126,11 +121,11 @@
pw.println(" Dumps Location Time Zone Manager state for tests as text or binary proto"
+ " form.");
pw.println(" See the LocationTimeZoneManagerServiceStateProto definition for details.");
- pw.printf(" %s <provider name> <test command>\n",
+ pw.printf(" %s <provider index> <test command>\n",
SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
pw.println(" Passes a test command to the named provider.");
pw.println();
- pw.printf("<provider name> = One of %s\n", VALID_PROVIDER_NAMES);
+ pw.println("<provider index> = 0 (primary), 1 (secondary)");
pw.println();
pw.printf("%s details:\n", SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
pw.println();
@@ -146,6 +141,47 @@
pw.println();
pw.println("Test commands cannot currently be passed to real provider implementations.");
pw.println();
+ pw.printf("This service is also affected by the following device_config flags in the"
+ + " %s namespace:\n", NAMESPACE_SYSTEM_TIME);
+ pw.printf(" %s - [default=true], only observed if the feature is enabled in config,"
+ + "set this to false to disable the feature\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED);
+ pw.printf(" %s - [default=false]. Only used if the device does not have an explicit"
+ + " 'location time zone detection enabled' setting configured [*].\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT);
+ pw.printf(" %s - [default=<unset>]. Used to override the device's 'location time zone"
+ + " detection enabled' setting [*]\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
+ pw.printf(" %s - Overrides the mode of the primary provider. Values=%s|%s|%s\n",
+ KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED);
+ pw.printf(" %s - Overrides the mode of the secondary provider. Values=%s|%s|%s\n",
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED);
+ pw.printf(" %s - \n",
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE);
+ pw.printf(" %s - Sets the amount of time the service waits when uncertain before making"
+ + " an 'uncertain' suggestion to the time zone detector.\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS);
+ pw.printf(" %s - Sets the initialization time passed to the location time zone providers"
+ + "\n",
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS);
+ pw.printf(" %s - Sets the amount of extra time added to the location time zone providers"
+ + " initialization time\n",
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS);
+ pw.println();
+ pw.println("[*] The user must still have location = on / auto time zone detection = on");
+ pw.println();
+ pw.printf("Typically, use '%s' to stop the service before setting individual"
+ + " flags and '%s' after to restart it.\n",
+ SHELL_COMMAND_STOP, SHELL_COMMAND_START);
+ pw.println();
+ pw.println("Example:");
+ pw.printf(" $ adb shell cmd device_config put %s %s %s\n",
+ NAMESPACE_SYSTEM_TIME, KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+ "true");
+ pw.println("See adb shell cmd device_config for more information.");
+ pw.println();
}
private int runStart() {
@@ -172,21 +208,6 @@
return 0;
}
- private int runSetProviderModeOverride() {
- PrintWriter outPrintWriter = getOutPrintWriter();
- try {
- String providerName = getNextArgRequired();
- String modeOverride = getNextArgRequired();
- outPrintWriter.println("Setting provider mode override for " + providerName
- + " to " + modeOverride);
- mService.setProviderModeOverride(providerName, modeOverride);
- } catch (RuntimeException e) {
- reportError(e);
- return 1;
- }
- return 0;
- }
-
private int runRecordProviderStates() {
PrintWriter outPrintWriter = getOutPrintWriter();
boolean enabled;
@@ -293,10 +314,10 @@
private int runSendProviderTestCommand() {
PrintWriter outPrintWriter = getOutPrintWriter();
- String providerName;
+ int providerIndex;
TestCommand testCommand;
try {
- providerName = validateProviderName(getNextArgRequired());
+ providerIndex = parseProviderIndex(getNextArgRequired());
testCommand = createTestCommandFromNextShellArg();
} catch (RuntimeException e) {
reportError(e);
@@ -304,9 +325,9 @@
}
outPrintWriter.println("Injecting testCommand=" + testCommand
- + " to providerName=" + providerName);
+ + " to providerIndex=" + providerIndex);
try {
- Bundle result = mService.handleProviderTestCommand(providerName, testCommand);
+ Bundle result = mService.handleProviderTestCommand(providerIndex, testCommand);
outPrintWriter.println(result);
} catch (RuntimeException e) {
reportError(e);
@@ -326,11 +347,11 @@
e.printStackTrace(errPrintWriter);
}
- @NonNull
- static String validateProviderName(@NonNull String value) {
- if (!VALID_PROVIDER_NAMES.contains(value)) {
- throw new IllegalArgumentException("Unknown provider name=" + value);
+ private static int parseProviderIndex(@NonNull String providerIndexString) {
+ int providerIndex = Integer.parseInt(providerIndexString);
+ if (providerIndex < 0 || providerIndex > 1) {
+ throw new IllegalArgumentException(providerIndexString);
}
- return value;
+ return providerIndex;
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
index 6c3f016..b5ac712 100644
--- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
@@ -62,15 +62,17 @@
RealLocationTimeZoneProviderProxy(
@NonNull Context context, @NonNull Handler handler,
@NonNull ThreadingDomain threadingDomain, @NonNull String action,
- int enableOverlayResId, int nonOverlayPackageResId) {
+ @NonNull String providerPackageName) {
super(context, threadingDomain);
mManagerProxy = null;
mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
+
+ Objects.requireNonNull(providerPackageName);
mServiceWatcher = ServiceWatcher.create(context,
handler,
"RealLocationTimeZoneProviderProxy",
- new CurrentUserServiceSupplier(context, action, enableOverlayResId,
- nonOverlayPackageResId, BIND_TIME_ZONE_PROVIDER_SERVICE,
+ new CurrentUserServiceSupplier(context, action,
+ providerPackageName, BIND_TIME_ZONE_PROVIDER_SERVICE,
INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE),
this);
}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index ae806aa..7bc6056 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -38,6 +38,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -328,6 +329,8 @@
private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) {
+ Slog.v(getLogTag(), "Received request " + request);
+
if (score > getNetworkScore()) {
if (VDBG) {
Slog.v(
@@ -409,6 +412,26 @@
return TAG + " [" + mSubscriptionGroup.hashCode() + "]";
}
+ /**
+ * Dumps the state of this Vcn for logging and debugging purposes.
+ *
+ * <p>PII and credentials MUST NEVER be dumped here.
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("Vcn (" + mSubscriptionGroup + "):");
+ pw.increaseIndent();
+
+ pw.println("mCurrentStatus: " + mCurrentStatus);
+
+ pw.println("mVcnGatewayConnections:");
+ for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
+ gw.dump(pw);
+ }
+ pw.println();
+
+ pw.decreaseIndent();
+ }
+
/** Retrieves the network score for a VCN Network */
// Package visibility for use in VcnGatewayConnection
static int getNetworkScore() {
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 20c08eb..83ac36f 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -77,6 +77,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
@@ -84,6 +85,7 @@
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.util.MtuUtils;
import java.io.IOException;
import java.net.Inet4Address;
@@ -448,6 +450,44 @@
*/
private static final int EVENT_SAFE_MODE_TIMEOUT_EXCEEDED = 10;
+ /**
+ * Sent when an IKE has completed migration, and created updated transforms for application.
+ *
+ * <p>Only relevant in the Connected state.
+ *
+ * @param arg1 The session token for the IKE Session that completed migration, used to prevent
+ * out-of-date signals from propagating.
+ * @param obj @NonNull An EventMigrationCompletedInfo instance with relevant data.
+ */
+ private static final int EVENT_MIGRATION_COMPLETED = 11;
+
+ private static class EventMigrationCompletedInfo implements EventInfo {
+ @NonNull public final IpSecTransform inTransform;
+ @NonNull public final IpSecTransform outTransform;
+
+ EventMigrationCompletedInfo(
+ @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform) {
+ this.inTransform = Objects.requireNonNull(inTransform);
+ this.outTransform = Objects.requireNonNull(outTransform);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(inTransform, outTransform);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof EventMigrationCompletedInfo)) {
+ return false;
+ }
+
+ final EventMigrationCompletedInfo rhs = (EventMigrationCompletedInfo) other;
+ return Objects.equals(inTransform, rhs.inTransform)
+ && Objects.equals(outTransform, rhs.outTransform);
+ }
+ }
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
@NonNull
final DisconnectedState mDisconnectedState = new DisconnectedState();
@@ -574,7 +614,7 @@
* <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
* otherwise.
*/
- private NetworkAgent mNetworkAgent;
+ private VcnNetworkAgent mNetworkAgent;
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
@Nullable private WakeupMessage mDisconnectRequestAlarm;
@@ -1053,6 +1093,14 @@
sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, token);
}
+ private void migrationCompleted(
+ int token, @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform) {
+ sendMessageAndAcquireWakeLock(
+ EVENT_MIGRATION_COMPLETED,
+ token,
+ new EventMigrationCompletedInfo(inTransform, outTransform));
+ }
+
private void childTransformCreated(
int token, @NonNull IpSecTransform transform, int direction) {
sendMessageAndAcquireWakeLock(
@@ -1148,7 +1196,9 @@
case EVENT_SETUP_COMPLETED: // Fallthrough
case EVENT_DISCONNECT_REQUESTED: // Fallthrough
case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough
- case EVENT_SUBSCRIPTIONS_CHANGED:
+ case EVENT_SUBSCRIPTIONS_CHANGED: // Fallthrough
+ case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: // Fallthrough
+ case EVENT_MIGRATION_COMPLETED:
logUnexpectedEvent(msg.what);
break;
default:
@@ -1440,30 +1490,32 @@
private abstract class ConnectedStateBase extends ActiveBaseState {
protected void updateNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull NetworkAgent agent,
+ @NonNull VcnNetworkAgent agent,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
- buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
+ buildConnectedLinkProperties(
+ mConnectionConfig, tunnelIface, childConfig, mUnderlying);
agent.sendNetworkCapabilities(caps);
agent.sendLinkProperties(lp);
}
- protected NetworkAgent buildNetworkAgent(
+ protected VcnNetworkAgent buildNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
- buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
+ buildConnectedLinkProperties(
+ mConnectionConfig, tunnelIface, childConfig, mUnderlying);
final NetworkAgentConfig nac =
new NetworkAgentConfig.Builder()
.setLegacyType(ConnectivityManager.TYPE_MOBILE)
.build();
- final NetworkAgent agent =
+ final VcnNetworkAgent agent =
mDeps.newNetworkAgent(
mVcnContext,
TAG,
@@ -1472,15 +1524,21 @@
Vcn.getNetworkScore(),
nac,
mVcnContext.getVcnNetworkProvider(),
- () -> {
- Slog.d(TAG, "NetworkAgent was unwanted");
- // If network agent has already been torn down, skip sending the
- // disconnect. Unwanted() is always called, even when networkAgents
- // are unregistered in teardownNetwork(), so prevent duplicate
- // notifications.
- if (mNetworkAgent != null) {
- teardownAsynchronously();
+ (agentRef) -> {
+ // Only trigger teardown if the NetworkAgent hasn't been replaced or
+ // changed. This guards against two cases - the first where
+ // unwanted() may be called as a result of the
+ // NetworkAgent.unregister() call, which might trigger a teardown
+ // instead of just a Network disconnect, as well as the case where a
+ // new NetworkAgent replaces an old one before the unwanted() call
+ // is processed.
+ if (mNetworkAgent != agentRef) {
+ Slog.d(TAG, "unwanted() called on stale NetworkAgent");
+ return;
}
+
+ Slog.d(TAG, "NetworkAgent was unwanted");
+ teardownAsynchronously();
} /* networkUnwantedCallback */,
(status) -> {
if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
@@ -1620,12 +1678,36 @@
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
handleSafeModeTimeoutExceeded();
break;
+ case EVENT_MIGRATION_COMPLETED:
+ final EventMigrationCompletedInfo migrationCompletedInfo =
+ (EventMigrationCompletedInfo) msg.obj;
+
+ handleMigrationCompleted(migrationCompletedInfo);
+ break;
default:
logUnhandledMessage(msg);
break;
}
}
+ private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) {
+ applyTransform(
+ mCurrentToken,
+ mTunnelIface,
+ mUnderlying.network,
+ migrationCompletedInfo.inTransform,
+ IpSecManager.DIRECTION_IN);
+
+ applyTransform(
+ mCurrentToken,
+ mTunnelIface,
+ mUnderlying.network,
+ migrationCompletedInfo.outTransform,
+ IpSecManager.DIRECTION_OUT);
+
+ updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig);
+ }
+
private void handleUnderlyingNetworkChanged(@NonNull Message msg) {
final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
@@ -1815,7 +1897,10 @@
private static LinkProperties buildConnectedLinkProperties(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull VcnChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @Nullable UnderlyingNetworkRecord underlying) {
+ final VcnControlPlaneIkeConfig controlPlaneConfig =
+ (VcnControlPlaneIkeConfig) gatewayConnectionConfig.getControlPlaneConfig();
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -1831,7 +1916,12 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
null /*iface*/, RouteInfo.RTN_UNICAST));
- lp.setMtu(gatewayConnectionConfig.getMaxMtu());
+ final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu();
+ lp.setMtu(
+ MtuUtils.getMtu(
+ controlPlaneConfig.getChildSessionParams().getSaProposals(),
+ gatewayConnectionConfig.getMaxMtu(),
+ underlyingMtu));
return lp;
}
@@ -1912,8 +2002,7 @@
@NonNull IpSecTransform inIpSecTransform,
@NonNull IpSecTransform outIpSecTransform) {
Slog.v(TAG, "ChildTransformsMigrated; token " + mToken);
- onIpSecTransformCreated(inIpSecTransform, IpSecManager.DIRECTION_IN);
- onIpSecTransformCreated(outIpSecTransform, IpSecManager.DIRECTION_OUT);
+ migrationCompleted(mToken, inIpSecTransform, outIpSecTransform);
}
@Override
@@ -1924,6 +2013,27 @@
}
}
+ /**
+ * Dumps the state of this VcnGatewayConnection for logging and debugging purposes.
+ *
+ * <p>PII and credentials MUST NEVER be dumped here.
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("VcnGatewayConnection (" + mConnectionConfig.getGatewayConnectionName() + "):");
+ pw.increaseIndent();
+
+ pw.println("Current state: " + getCurrentState().getClass().getSimpleName());
+ pw.println("mIsQuitting: " + mIsQuitting);
+ pw.println("mIsInSafeMode: " + mIsInSafeMode);
+ pw.println("mCurrentToken: " + mCurrentToken);
+ pw.println("mFailedAttempts: " + mFailedAttempts);
+ pw.println(
+ "mNetworkAgent.getNetwork(): "
+ + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
+
+ pw.decreaseIndent();
+ }
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
void setTunnelInterface(IpSecTunnelInterface tunnelIface) {
mTunnelIface = tunnelIface;
@@ -1965,12 +2075,12 @@
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
- NetworkAgent getNetworkAgent() {
+ VcnNetworkAgent getNetworkAgent() {
return mNetworkAgent;
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
- void setNetworkAgent(@Nullable NetworkAgent networkAgent) {
+ void setNetworkAgent(@Nullable VcnNetworkAgent networkAgent) {
mNetworkAgent = networkAgent;
}
@@ -2058,8 +2168,8 @@
return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
}
- /** Builds a new NetworkAgent. */
- public NetworkAgent newNetworkAgent(
+ /** Builds a new VcnNetworkAgent. */
+ public VcnNetworkAgent newNetworkAgent(
@NonNull VcnContext vcnContext,
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@@ -2067,27 +2177,18 @@
@NonNull int score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
- @NonNull Runnable networkUnwantedCallback,
+ @NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
@NonNull Consumer<Integer> validationStatusCallback) {
- return new NetworkAgent(
- vcnContext.getContext(),
- vcnContext.getLooper(),
+ return new VcnNetworkAgent(
+ vcnContext,
tag,
caps,
lp,
score,
nac,
- provider) {
- @Override
- public void onNetworkUnwanted() {
- networkUnwantedCallback.run();
- }
-
- @Override
- public void onValidationStatus(int status, @Nullable Uri redirectUri) {
- validationStatusCallback.accept(status);
- }
- };
+ provider,
+ networkUnwantedCallback,
+ validationStatusCallback);
}
/** Gets the elapsed real time since boot, in millis. */
@@ -2203,4 +2304,73 @@
mImpl.release();
}
}
+
+ /** Proxy Implementation of NetworkAgent, used for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class VcnNetworkAgent {
+ private final NetworkAgent mImpl;
+
+ public VcnNetworkAgent(
+ @NonNull VcnContext vcnContext,
+ @NonNull String tag,
+ @NonNull NetworkCapabilities caps,
+ @NonNull LinkProperties lp,
+ @NonNull int score,
+ @NonNull NetworkAgentConfig nac,
+ @NonNull NetworkProvider provider,
+ @NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
+ @NonNull Consumer<Integer> validationStatusCallback) {
+ mImpl =
+ new NetworkAgent(
+ vcnContext.getContext(),
+ vcnContext.getLooper(),
+ tag,
+ caps,
+ lp,
+ score,
+ nac,
+ provider) {
+ @Override
+ public void onNetworkUnwanted() {
+ networkUnwantedCallback.accept(VcnNetworkAgent.this);
+ }
+
+ @Override
+ public void onValidationStatus(int status, @Nullable Uri redirectUri) {
+ validationStatusCallback.accept(status);
+ }
+ };
+ }
+
+ /** Registers the underlying NetworkAgent */
+ public void register() {
+ mImpl.register();
+ }
+
+ /** Marks the underlying NetworkAgent as connected */
+ public void markConnected() {
+ mImpl.markConnected();
+ }
+
+ /** Unregisters the underlying NetworkAgent */
+ public void unregister() {
+ mImpl.unregister();
+ }
+
+ /** Sends new NetworkCapabilities for the underlying NetworkAgent */
+ public void sendNetworkCapabilities(@NonNull NetworkCapabilities caps) {
+ mImpl.sendNetworkCapabilities(caps);
+ }
+
+ /** Sends new LinkProperties for the underlying NetworkAgent */
+ public void sendLinkProperties(@NonNull LinkProperties lp) {
+ mImpl.sendLinkProperties(lp);
+ }
+
+ /** Retrieves the Network for the underlying NetworkAgent */
+ @Nullable
+ public Network getNetwork() {
+ return mImpl.getNetwork();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index a909695..be0deb5 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -29,6 +29,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import java.util.Objects;
import java.util.Set;
@@ -129,10 +130,50 @@
mScore = score;
mProviderId = providerId;
}
+
+ /**
+ * Dumps the state of this NetworkRequestEntry for logging and debugging purposes.
+ *
+ * <p>PII and credentials MUST NEVER be dumped here.
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("NetworkRequestEntry:");
+ pw.increaseIndent();
+
+ pw.println("mRequest: " + mRequest);
+ pw.println("mScore: " + mScore);
+ pw.println("mProviderId: " + mProviderId);
+
+ pw.decreaseIndent();
+ }
}
// package-private
interface NetworkRequestListener {
void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId);
}
+
+ /**
+ * Dumps the state of this VcnNetworkProvider for logging and debugging purposes.
+ *
+ * <p>PII and credentials MUST NEVER be dumped here.
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("VcnNetworkProvider:");
+ pw.increaseIndent();
+
+ pw.println("mListeners:");
+ for (NetworkRequestListener listener : mListeners) {
+ pw.println(listener);
+ }
+ pw.println();
+
+ pw.println("mRequests.values:");
+ for (NetworkRequestEntry entry : mRequests.values()) {
+ entry.dump(pw);
+ }
+ pw.println();
+
+ pw.decreaseIndent();
+ }
}
diff --git a/services/core/java/com/android/server/vcn/util/MtuUtils.java b/services/core/java/com/android/server/vcn/util/MtuUtils.java
new file mode 100644
index 0000000..49c1a02
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/util/MtuUtils.java
@@ -0,0 +1,155 @@
+/*
+ * 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.server.vcn.util;
+
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CTR;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE;
+
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
+
+import static java.lang.Math.max;
+import static java.util.Collections.unmodifiableMap;
+
+import android.annotation.NonNull;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.util.Slog;
+
+import java.util.List;
+import java.util.Map;
+
+/** @hide */
+public class MtuUtils {
+ private static final String TAG = MtuUtils.class.getSimpleName();
+ /**
+ * Max ESP overhead possible
+ *
+ * <p>60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad + NextHeader)
+ */
+ private static final int GENERIC_ESP_OVERHEAD_MAX = 78;
+
+ /** Maximum overheads of authentication algorithms, keyed on IANA-defined constants */
+ private static final Map<Integer, Integer> AUTH_ALGORITHM_OVERHEAD;
+
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(INTEGRITY_ALGORITHM_NONE, 0);
+ map.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, 12);
+ map.put(INTEGRITY_ALGORITHM_AES_XCBC_96, 12);
+ map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, 32);
+ map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, 48);
+ map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, 64);
+ map.put(INTEGRITY_ALGORITHM_AES_CMAC_96, 12);
+
+ AUTH_ALGORITHM_OVERHEAD = unmodifiableMap(map);
+ }
+
+ /** Maximum overheads of encryption algorithms, keyed on IANA-defined constants */
+ private static final Map<Integer, Integer> CRYPT_ALGORITHM_OVERHEAD;
+
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(ENCRYPTION_ALGORITHM_3DES, 15); // 8 (IV) + 7 (Max pad)
+ map.put(ENCRYPTION_ALGORITHM_AES_CBC, 31); // 16 (IV) + 15 (Max pad)
+ map.put(ENCRYPTION_ALGORITHM_AES_CTR, 11); // 8 (IV) + 3 (Max pad)
+
+ CRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map);
+ }
+
+ /** Maximum overheads of combined mode algorithms, keyed on IANA-defined constants */
+ private static final Map<Integer, Integer> AUTHCRYPT_ALGORITHM_OVERHEAD;
+
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(ENCRYPTION_ALGORITHM_AES_GCM_8, 19); // 8 (IV) + 3 (Max pad) + 8 (ICV)
+ map.put(ENCRYPTION_ALGORITHM_AES_GCM_12, 23); // 8 (IV) + 3 (Max pad) + 12 (ICV)
+ map.put(ENCRYPTION_ALGORITHM_AES_GCM_16, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV)
+ map.put(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV)
+
+ AUTHCRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map);
+ }
+
+ /**
+ * Calculates the MTU of the inner interface based on the parameters provided
+ *
+ * <p>The MTU of the inner interface will be the minimum of the following:
+ *
+ * <ul>
+ * <li>The MTU of the outer interface, minus the greatest ESP overhead (based on proposed
+ * algorithms).
+ * <li>The maximum MTU as provided in the arguments.
+ * </ul>
+ */
+ public static int getMtu(
+ @NonNull List<ChildSaProposal> childProposals, int maxMtu, int underlyingMtu) {
+ if (underlyingMtu <= 0) {
+ return IPV6_MIN_MTU;
+ }
+
+ boolean hasUnknownAlgorithm = false;
+ int maxAuthOverhead = 0;
+ int maxCryptOverhead = 0;
+ int maxAuthCryptOverhead = 0;
+
+ for (ChildSaProposal proposal : childProposals) {
+ for (Pair<Integer, Integer> encryptionAlgoPair : proposal.getEncryptionAlgorithms()) {
+ final int algo = encryptionAlgoPair.first;
+
+ if (AUTHCRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) {
+ maxAuthCryptOverhead =
+ max(maxAuthCryptOverhead, AUTHCRYPT_ALGORITHM_OVERHEAD.get(algo));
+ continue;
+ } else if (CRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) {
+ maxCryptOverhead = max(maxCryptOverhead, CRYPT_ALGORITHM_OVERHEAD.get(algo));
+ continue;
+ }
+
+ Slog.wtf(TAG, "Unknown encryption algorithm requested: " + algo);
+ return IPV6_MIN_MTU;
+ }
+
+ for (int algo : proposal.getIntegrityAlgorithms()) {
+ if (AUTH_ALGORITHM_OVERHEAD.containsKey(algo)) {
+ maxAuthOverhead = max(maxAuthOverhead, AUTH_ALGORITHM_OVERHEAD.get(algo));
+ continue;
+ }
+
+ Slog.wtf(TAG, "Unknown integrity algorithm requested: " + algo);
+ return IPV6_MIN_MTU;
+ }
+ }
+
+ // Return minimum of maxMtu, and the adjusted MTUs based on algorithms.
+ final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - GENERIC_ESP_OVERHEAD_MAX;
+ final int normalModeMtu =
+ underlyingMtu - maxCryptOverhead - maxAuthOverhead - GENERIC_ESP_OVERHEAD_MAX;
+ return Math.min(Math.min(maxMtu, combinedModeMtu), normalModeMtu);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 01a46b3..376595b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1887,6 +1887,14 @@
return selectedTheme;
}
+ // Whether this activity launched from system or Home or SystemUI
+ private boolean launchedFromSystemSurface() {
+ return launchedFromUid == Process.SYSTEM_UID || launchedFromUid == Process.ROOT_UID
+ || launchedFromHomeProcess
+ || mAtmService.getSysUiServiceComponentLocked().getPackageName().equals(
+ launchedFromPackage);
+ }
+
private boolean validateStartingWindowTheme(String pkg, int theme) {
// If this is a translucent window, then don't show a starting window -- the current
// effect (a full-screen opaque starting window that fades away to the real contents
@@ -1913,7 +1921,9 @@
"Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
windowIsTranslucent, windowIsFloating, windowShowWallpaper,
windowDisableStarting);
- if (windowIsTranslucent || windowIsFloating || windowDisableStarting) {
+ // If this activity is launched from system surface, ignore windowDisableStarting
+ if (windowIsTranslucent || windowIsFloating
+ || (windowDisableStarting && !launchedFromSystemSurface())) {
return false;
}
if (windowShowWallpaper
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index fe728ab..fb664ab 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -60,7 +60,7 @@
const std::string instance = std::string() + IStats::descriptor + "/default";
const binder_exception_t err =
AServiceManager_addService(statsService->asBinder().get(), instance.c_str());
- LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register %s: %d", instance.c_str(), err);
+ LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register AIDL %s: %d", instance.c_str(), err);
}
static void startStatsHidlService() {
@@ -69,13 +69,18 @@
android::sp<IStats> statsHal = new StatsHal();
const android::status_t err = statsHal->registerAsService();
- LOG_ALWAYS_FATAL_IF(err != android::OK, "Cannot register %s: %d", IStats::descriptor, err);
+ LOG_ALWAYS_FATAL_IF(err != android::OK, "Cannot register HIDL %s: %d", IStats::descriptor, err);
}
} // namespace
namespace android {
+static void android_server_SystemServer_startIStatsService(JNIEnv* /* env */, jobject /* clazz */) {
+ startStatsHidlService();
+ startStatsAidlService();
+}
+
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsensorservice", propBuf, "1");
@@ -129,9 +134,6 @@
} else {
ALOGW("%s is deprecated. Skipping registration.", ISchedulingPolicyService::descriptor);
}
-
- startStatsAidlService();
- startStatsHidlService();
}
static void android_server_SystemServer_initZygoteChildHeapProfiling(JNIEnv* /* env */,
@@ -160,6 +162,7 @@
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
+ {"startIStatsService", "()V", (void*)android_server_SystemServer_startIStatsService},
{"startSensorService", "()V", (void*)android_server_SystemServer_startSensorService},
{"startMemtrackProxyService", "()V",
(void*)android_server_SystemServer_startMemtrackProxyService},
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 63488f9..f843ea4 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -150,6 +150,11 @@
return ok();
}
+binder::Status BinderIncrementalService::onInstallationComplete(int32_t storageId) {
+ mImpl.onInstallationComplete(storageId);
+ return ok();
+}
+
binder::Status BinderIncrementalService::makeBindMount(int32_t storageId,
const std::string& sourcePath,
const std::string& targetFullPath,
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index ebb23dc..5c8741b 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -52,6 +52,8 @@
const ::android::sp<IStorageHealthListener>& healthListener,
const ::std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts,
bool* _aidl_return) final;
+ binder::Status onInstallationComplete(int32_t storageId) final;
+
binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath,
const std::string& targetFullPath, int32_t bindType,
int32_t* _aidl_return) final;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 6695ba8..388f932 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -100,6 +100,12 @@
return (s & (Constants::blockSize - 1)) == 0;
}
+static bool getAlwaysEnableReadTimeoutsForSystemDataLoaders() {
+ return android::base::
+ GetBoolProperty("debug.incremental.always_enable_read_timeouts_for_system_dataloaders",
+ true);
+}
+
static bool getEnforceReadLogsMaxIntervalForSystemDataLoaders() {
return android::base::GetBoolProperty("debug.incremental.enforce_readlogs_max_interval_for_"
"system_dataloaders",
@@ -315,19 +321,11 @@
::rmdir(path::c_str(root));
}
-void IncrementalService::IncFsMount::setReadLogsEnabled(bool value) {
+void IncrementalService::IncFsMount::setFlag(StorageFlags flag, bool value) {
if (value) {
- flags |= StorageFlags::ReadLogsEnabled;
+ flags |= flag;
} else {
- flags &= ~StorageFlags::ReadLogsEnabled;
- }
-}
-
-void IncrementalService::IncFsMount::setReadLogsRequested(bool value) {
- if (value) {
- flags |= StorageFlags::ReadLogsRequested;
- } else {
- flags &= ~StorageFlags::ReadLogsRequested;
+ flags &= ~flag;
}
}
@@ -728,10 +726,17 @@
LOG(INFO) << "Skipped data loader stub creation because it already exists";
return false;
}
+
prepareDataLoaderLocked(*ifs, std::move(dataLoaderParams), std::move(statusListener),
healthCheckParams, std::move(healthListener));
CHECK(ifs->dataLoaderStub);
dataLoaderStub = ifs->dataLoaderStub;
+
+ // Disable long read timeouts for non-system dataloaders.
+ // To be re-enabled after installation is complete.
+ ifs->setReadTimeoutsRequested(dataLoaderStub->isSystemDataLoader() &&
+ getAlwaysEnableReadTimeoutsForSystemDataLoaders());
+ applyStorageParamsLocked(*ifs);
}
if (dataLoaderStub->isSystemDataLoader() &&
@@ -765,6 +770,18 @@
return dataLoaderStub->requestStart();
}
+void IncrementalService::onInstallationComplete(StorageId storage) {
+ IfsMountPtr ifs = getIfs(storage);
+ if (!ifs) {
+ return;
+ }
+
+ // Always enable long read timeouts after installation is complete.
+ std::unique_lock l(ifs->lock);
+ ifs->setReadTimeoutsRequested(true);
+ applyStorageParamsLocked(*ifs);
+}
+
IncrementalService::BindPathMap::const_iterator IncrementalService::findStorageLocked(
std::string_view path) const {
return findParentPath(mBindsByPath, path);
@@ -868,7 +885,7 @@
if (!ifs->readLogsRequested()) {
return 0;
}
- if (auto status = applyStorageParamsLocked(*ifs, /*enableReadLogs=*/true); status != 0) {
+ if (auto status = applyStorageParamsLocked(*ifs); status != 0) {
return status;
}
}
@@ -880,10 +897,10 @@
int IncrementalService::disableReadLogsLocked(IncFsMount& ifs) {
ifs.setReadLogsRequested(false);
- return applyStorageParamsLocked(ifs, /*enableReadLogs=*/false);
+ return applyStorageParamsLocked(ifs);
}
-int IncrementalService::applyStorageParamsLocked(IncFsMount& ifs, bool enableReadLogs) {
+int IncrementalService::applyStorageParamsLocked(IncFsMount& ifs) {
os::incremental::IncrementalFileSystemControlParcel control;
control.cmd.reset(dup(ifs.control.cmd()));
control.pendingReads.reset(dup(ifs.control.pendingReads()));
@@ -892,11 +909,15 @@
control.log.reset(dup(logsFd));
}
+ bool enableReadLogs = ifs.readLogsRequested();
+ bool enableReadTimeouts = ifs.readTimeoutsRequested();
+
std::lock_guard l(mMountOperationLock);
- auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
+ auto status = mVold->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts);
if (status.isOk()) {
- // Store enabled state.
+ // Store states.
ifs.setReadLogsEnabled(enableReadLogs);
+ ifs.setReadTimeoutsEnabled(enableReadTimeouts);
} else {
LOG(ERROR) << "applyStorageParams failed: " << status.toString8();
}
@@ -1271,7 +1292,7 @@
maxPendingTimeUs = std::max(maxPendingTimeUs, microseconds(timeouts.maxPendingTimeUs));
}
if (maxPendingTimeUs < Constants::minPerUidTimeout) {
- LOG(ERROR) << "Skip setting read timeouts (maxPendingTime < Constants::minPerUidTimeout): "
+ LOG(ERROR) << "Skip setting read timeouts (maxPendingTime < Constants::minPerUidTimeout): "
<< duration_cast<milliseconds>(maxPendingTimeUs).count() << "ms < "
<< Constants::minPerUidTimeout.count() << "ms";
return;
@@ -2946,8 +2967,10 @@
return result;
}
- LOG(DEBUG) << id() << ": pendingReads: " << control.pendingReads() << ", "
- << mLastPendingReads.size() << ": " << mLastPendingReads.front().bootClockTsUs;
+ LOG(DEBUG) << id() << ": pendingReads: fd(" << control.pendingReads() << "), count("
+ << mLastPendingReads.size() << "), block: " << mLastPendingReads.front().block
+ << ", time: " << mLastPendingReads.front().bootClockTsUs
+ << ", uid: " << mLastPendingReads.front().uid;
return getOldestTsFromLastPendingReads();
}
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index fb6f56c..e3b1e6f 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -118,6 +118,9 @@
ReadLogsAllowed = 1 << 0,
ReadLogsEnabled = 1 << 1,
ReadLogsRequested = 1 << 2,
+
+ ReadTimeoutsEnabled = 1 << 3,
+ ReadTimeoutsRequested = 1 << 4,
};
struct LoadingProgress {
@@ -160,6 +163,7 @@
const StorageHealthCheckParams& healthCheckParams,
StorageHealthListener healthListener,
std::vector<PerUidReadTimeouts> perUidReadTimeouts);
+ void onInstallationComplete(StorageId storage);
int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind);
int unbind(StorageId storage, std::string_view target);
@@ -316,7 +320,7 @@
} mHealthBase = {TimePoint::max(), kMaxBootClockTsUs};
StorageHealthCheckParams mHealthCheckParams;
int mStreamStatus = content::pm::IDataLoaderStatusListener::STREAM_HEALTHY;
- std::vector<incfs::ReadInfo> mLastPendingReads;
+ std::vector<incfs::ReadInfoWithUid> mLastPendingReads;
};
using DataLoaderStubPtr = sp<DataLoaderStub>;
@@ -364,13 +368,32 @@
void disallowReadLogs() { flags &= ~StorageFlags::ReadLogsAllowed; }
int32_t readLogsAllowed() const { return (flags & StorageFlags::ReadLogsAllowed); }
- void setReadLogsEnabled(bool value);
+ void setReadLogsEnabled(bool value) {
+ return setFlag(StorageFlags::ReadLogsEnabled, value);
+ }
int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); }
- void setReadLogsRequested(bool value);
+ void setReadLogsRequested(bool value) {
+ return setFlag(StorageFlags::ReadLogsRequested, value);
+ }
int32_t readLogsRequested() const { return (flags & StorageFlags::ReadLogsRequested); }
+ void setReadTimeoutsEnabled(bool value) {
+ return setFlag(StorageFlags::ReadTimeoutsEnabled, value);
+ }
+ int32_t readTimeoutsEnabled() const { return (flags & StorageFlags::ReadTimeoutsEnabled); }
+
+ void setReadTimeoutsRequested(bool value) {
+ return setFlag(StorageFlags::ReadTimeoutsRequested, value);
+ }
+ int32_t readTimeoutsRequested() const {
+ return (flags & StorageFlags::ReadTimeoutsRequested);
+ }
+
static void cleanupFilesystem(std::string_view root);
+
+ private:
+ void setFlag(StorageFlags flag, bool value);
};
using IfsMountPtr = std::shared_ptr<IncFsMount>;
@@ -422,7 +445,7 @@
int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
int disableReadLogsLocked(IncFsMount& ifs);
- int applyStorageParamsLocked(IncFsMount& ifs, bool enableReadLogs);
+ int applyStorageParamsLocked(IncFsMount& ifs);
LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 8e416f3..0755a22 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -55,8 +55,8 @@
}
binder::Status setIncFsMountOptions(
const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
- bool enableReadLogs) const final {
- return mInterface->setIncFsMountOptions(control, enableReadLogs);
+ bool enableReadLogs, bool enableReadTimeouts) const final {
+ return mInterface->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts);
}
private:
@@ -233,8 +233,9 @@
ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const final {
return incfs::reserveSpace(control, id, size);
}
- WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final {
+ WaitResult waitForPendingReads(
+ const Control& control, std::chrono::milliseconds timeout,
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) const final {
return incfs::waitForPendingReads(control, timeout, pendingReadsBuffer);
}
ErrorCode setUidReadTimeouts(const Control& control,
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index d4cdcbe..78e9589 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -56,8 +56,8 @@
virtual binder::Status bindMount(const std::string& sourceDir,
const std::string& targetDir) const = 0;
virtual binder::Status setIncFsMountOptions(
- const os::incremental::IncrementalFileSystemControlParcel& control,
- bool enableReadLogs) const = 0;
+ const os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs,
+ bool enableReadTimeouts) const = 0;
};
class DataLoaderManagerWrapper {
@@ -117,7 +117,7 @@
virtual ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const = 0;
virtual WaitResult waitForPendingReads(
const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer) const = 0;
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) const = 0;
virtual ErrorCode setUidReadTimeouts(
const Control& control,
const std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts)
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 1ec446d..14bcd4e 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -56,10 +56,10 @@
MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
MOCK_CONST_METHOD2(bindMount,
binder::Status(const std::string& sourceDir, const std::string& argetDir));
- MOCK_CONST_METHOD2(
+ MOCK_CONST_METHOD3(
setIncFsMountOptions,
binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&,
- bool));
+ bool, bool));
void mountIncFsFails() {
ON_CALL(*this, mountIncFs(_, _, _, _))
@@ -83,12 +83,13 @@
ON_CALL(*this, bindMount(_, _)).WillByDefault(Return(binder::Status::ok()));
}
void setIncFsMountOptionsFails() const {
- ON_CALL(*this, setIncFsMountOptions(_, _))
+ ON_CALL(*this, setIncFsMountOptions(_, _, _))
.WillByDefault(Return(
binder::Status::fromExceptionCode(1, String8("failed to set options"))));
}
void setIncFsMountOptionsSuccess() {
- ON_CALL(*this, setIncFsMountOptions(_, _)).WillByDefault(Return(binder::Status::ok()));
+ ON_CALL(*this, setIncFsMountOptions(_, _, _))
+ .WillByDefault(Invoke(this, &MockVoldService::setIncFsMountOptionsOk));
}
binder::Status getInvalidControlParcel(const std::string& imagePath,
const std::string& targetDir, int32_t flags,
@@ -103,10 +104,23 @@
_aidl_return->log.reset(base::unique_fd(dup(STDIN_FILENO)));
return binder::Status::ok();
}
+ binder::Status setIncFsMountOptionsOk(
+ const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
+ bool enableReadLogs, bool enableReadTimeouts) {
+ mReadLogsEnabled = enableReadLogs;
+ mReadTimeoutsEnabled = enableReadTimeouts;
+ return binder::Status::ok();
+ }
+
+ bool readLogsEnabled() const { return mReadLogsEnabled; }
+ bool readTimeoutsEnabled() const { return mReadTimeoutsEnabled; }
private:
TemporaryFile cmdFile;
TemporaryFile logFile;
+
+ bool mReadLogsEnabled = false;
+ bool mReadTimeoutsEnabled = true;
};
class MockDataLoader : public IDataLoader {
@@ -395,7 +409,7 @@
MOCK_CONST_METHOD3(reserveSpace, ErrorCode(const Control& control, FileId id, IncFsSize size));
MOCK_CONST_METHOD3(waitForPendingReads,
WaitResult(const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer));
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer));
MOCK_CONST_METHOD2(setUidReadTimeouts,
ErrorCode(const Control& control,
const std::vector<PerUidReadTimeouts>& perUidReadTimeouts));
@@ -435,7 +449,7 @@
ON_CALL(*this, waitForPendingReads(_, _, _))
.WillByDefault(
Invoke([ts](const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer) {
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) {
pendingReadsBuffer->push_back({.bootClockTsUs = ts});
return android::incfs::WaitResult::HaveData;
}));
@@ -1302,8 +1316,10 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ // on startLoading
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
// We are calling setIncFsMountOptions(true).
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1325,8 +1341,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1353,8 +1369,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(2);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(2);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1394,8 +1410,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(3);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(3);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1435,8 +1451,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(3);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(5);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(3);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1448,9 +1464,14 @@
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ // Before install - long timeouts.
+ ASSERT_TRUE(mVold->readTimeoutsEnabled());
+
auto dataLoaderParcel = mDataLoaderParcel;
ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(dataLoaderParcel), {}, {},
{}, {}));
+ // During install - short timeouts.
+ ASSERT_FALSE(mVold->readTimeoutsEnabled());
// Disable readlogs callback present.
ASSERT_EQ(storageId, mTimedQueue->mId);
@@ -1463,9 +1484,15 @@
mClock->advance(90min);
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+ mIncrementalService->onInstallationComplete(storageId);
+ // After install - long timeouts.
+ ASSERT_TRUE(mVold->readTimeoutsEnabled());
+
// New installation.
ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
{}, {}));
+ // New installation - short timeouts.
+ ASSERT_FALSE(mVold->readTimeoutsEnabled());
// New callback present.
ASSERT_EQ(storageId, mTimedQueue->mId);
@@ -1485,6 +1512,10 @@
// And timeout.
mClock->advance(90min);
ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
+
+ mIncrementalService->onInstallationComplete(storageId);
+ // After install - long timeouts.
+ ASSERT_TRUE(mVold->readTimeoutsEnabled());
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
@@ -1495,9 +1526,9 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
// setIncFsMountOptions(false) is called on the callback.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// After callback is called, disable read logs and remove callback.
@@ -1520,7 +1551,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// checkPermission fails, no calls to set opitions, start or stop WatchingMode.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
@@ -1539,7 +1571,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// checkPermission fails, no calls to set opitions, start or stop WatchingMode.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
@@ -1559,7 +1592,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
// setIncFsMountOptions fails, no calls to start or stop WatchingMode.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9b2a1e7..1426579 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -442,15 +442,15 @@
private final SystemServerDumper mDumper = new SystemServerDumper();
-
/**
* The pending WTF to be logged into dropbox.
*/
private static LinkedList<Pair<String, ApplicationErrorReport.CrashInfo>> sPendingWtfs;
- /**
- * Start the sensor service. This is a blocking call and can take time.
- */
+ /** Start the IStats services. This is a blocking call and can take time. */
+ private static native void startIStatsService();
+
+ /** Start the sensor service. This is a blocking call and can take time. */
private static native void startSensorService();
/**
@@ -1029,6 +1029,10 @@
mSystemServiceManager.startService(PowerStatsService.class);
t.traceEnd();
+ t.traceBegin("StartIStatsService");
+ startIStatsService();
+ t.traceEnd();
+
// Start MemtrackProxyService before ActivityManager, so that early calls
// to Memtrack::getMemory() don't fail.
t.traceBegin("MemtrackProxyService");
@@ -2678,7 +2682,7 @@
t.traceBegin("RegisterAppOpsPolicy");
try {
- mActivityManagerService.setAppOpsPolicy(new AppOpsPolicy());
+ mActivityManagerService.setAppOpsPolicy(new AppOpsPolicy(mSystemContext));
} catch (Throwable e) {
reportWtf("registering app ops policy", e);
}
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 75614d6..9f24d9a 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -63,6 +63,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -105,6 +106,7 @@
public class DataManager {
private static final String TAG = "DataManager";
+ private static final boolean DEBUG = false;
private static final long RECENT_NOTIFICATIONS_MAX_AGE_MS = 10 * DateUtils.DAY_IN_MILLIS;
private static final long QUERY_EVENTS_MAX_AGE_MS = 5L * DateUtils.MINUTE_IN_MILLIS;
@@ -217,6 +219,7 @@
List<ShortcutInfo> shortcuts = getShortcuts(packageName, userId,
Collections.singletonList(shortcutId));
if (shortcuts != null && !shortcuts.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Found shortcut for " + shortcuts.get(0).getLabel());
return shortcuts.get(0);
}
return null;
@@ -258,6 +261,7 @@
}
ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
if (shortcutInfo == null) {
+ Slog.e(TAG, " Shortcut no longer found: " + shortcutId);
return null;
}
int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
@@ -705,6 +709,7 @@
}
});
for (String packageName : packagesToDelete) {
+ if (DEBUG) Log.d(TAG, "Deleting packages data for: " + packageName);
userData.deletePackageData(packageName);
}
}
@@ -716,6 +721,7 @@
@ShortcutQuery.QueryFlags int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
| ShortcutQuery.FLAG_MATCH_CACHED | ShortcutQuery.FLAG_GET_PERSONS_DATA;
+ if (DEBUG) Log.d(TAG, " Get shortcuts with IDs: " + shortcutIds);
return mShortcutServiceInternal.getShortcuts(
UserHandle.USER_SYSTEM, mContext.getPackageName(),
/*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
@@ -742,7 +748,7 @@
TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
String defaultDialer = telecomManager != null
? telecomManager.getDefaultDialerPackage(
- new UserHandle(userData.getUserId())) : null;
+ new UserHandle(userData.getUserId())) : null;
userData.setDefaultDialer(defaultDialer);
}
@@ -848,6 +854,9 @@
ConversationStore conversationStore = packageData.getConversationStore();
ConversationInfo oldConversationInfo =
conversationStore.getConversation(shortcutInfo.getId());
+ if (oldConversationInfo == null) {
+ if (DEBUG) Log.d(TAG, "Nothing previously stored about conversation.");
+ }
ConversationInfo.Builder builder = oldConversationInfo != null
? new ConversationInfo.Builder(oldConversationInfo)
: new ConversationInfo.Builder();
@@ -1083,6 +1092,7 @@
Set<String> shortcutIds = new HashSet<>();
for (ShortcutInfo shortcutInfo : shortcuts) {
if (packageData != null) {
+ if (DEBUG) Log.d(TAG, "Deleting shortcut: " + shortcutInfo.getId());
packageData.deleteDataForConversation(shortcutInfo.getId());
}
shortcutIds.add(shortcutInfo.getId());
@@ -1309,6 +1319,7 @@
int userId = getChangingUserId();
UserData userData = getUnlockedUserData(userId);
if (userData != null) {
+ if (DEBUG) Log.d(TAG, "Delete package data for: " + packageName);
userData.deletePackageData(packageName);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 557c14a..9937ec1 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -98,7 +97,7 @@
when(nextClient.getTargetUserId()).thenReturn(nextUserId);
mScheduler.scheduleClientMonitor(nextClient);
- verify(nextClient, never()).start(any());
+
assertEquals(0, mUserStoppedCallback.numInvocations);
assertEquals(1, mUserStartedCallback.numInvocations);
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 5e50bea..d250297 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -571,7 +571,7 @@
*
* @throws SecurityException if the caller does not have the required permission/privileges
*/
- public static void enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
+ public static void enforceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE)
== PERMISSION_GRANTED) {
@@ -591,7 +591,7 @@
*
* @throws SecurityException if the caller does not have the required permission/privileges
*/
- public static void enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+ public static void enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
== PERMISSION_GRANTED) {
@@ -613,7 +613,7 @@
*
* @throws SecurityException if the caller does not have the required permission/privileges
*/
- public static void enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ public static void enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
== PERMISSION_GRANTED) {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 34c0018..bb67593 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -26,6 +26,7 @@
import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -46,15 +47,19 @@
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.TemporaryFailureException;
+import android.net.vcn.VcnControlPlaneIkeConfig;
import android.net.vcn.VcnManager.VcnErrorCode;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.vcn.util.MtuUtils;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,13 +78,13 @@
@SmallTest
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
private VcnIkeSession mIkeSession;
- private NetworkAgent mNetworkAgent;
+ private VcnNetworkAgent mNetworkAgent;
@Before
public void setUp() throws Exception {
super.setUp();
- mNetworkAgent = mock(NetworkAgent.class);
+ mNetworkAgent = mock(VcnNetworkAgent.class);
doReturn(mNetworkAgent)
.when(mDeps)
.newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
@@ -152,7 +157,9 @@
}
@Test
- public void testMigratedTransformsAreApplied() throws Exception {
+ public void testMigration() throws Exception {
+ triggerChildOpened();
+
getChildSessionCallback()
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
mTestLooper.dispatchAll();
@@ -170,6 +177,17 @@
}
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+
+ final List<ChildSaProposal> saProposals =
+ ((VcnControlPlaneIkeConfig) mConfig.getControlPlaneConfig())
+ .getChildSessionParams()
+ .getSaProposals();
+ final int expectedMtu =
+ MtuUtils.getMtu(
+ saProposals,
+ mConfig.getMaxMtu(),
+ TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu());
+ verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu()));
}
private void triggerChildOpened() {
@@ -299,8 +317,9 @@
.removeAddressFromTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
- // TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties
- // is mockable
+ verify(mNetworkAgent).sendLinkProperties(argThat(
+ lp -> newInternalAddrs.equals(lp.getLinkAddresses())
+ && Collections.singletonList(TEST_DNS_ADDR_2).equals(lp.getDnsServers())));
// Verify that IpSecTunnelInterface only created once
verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
@@ -323,6 +342,66 @@
assertFalse(mGatewayConnection.isInSafeMode());
}
+ private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() {
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ final ArgumentCaptor<Consumer<VcnNetworkAgent>> unwantedCallbackCaptor =
+ ArgumentCaptor.forClass(Consumer.class);
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ any(),
+ anyInt(),
+ any(),
+ any(),
+ unwantedCallbackCaptor.capture(),
+ any());
+
+ return unwantedCallbackCaptor.getValue();
+ }
+
+ @Test
+ public void testUnwantedNetworkAgentTriggersTeardown() throws Exception {
+ final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
+
+ unwantedCallback.accept(mNetworkAgent);
+ mTestLooper.dispatchAll();
+
+ assertTrue(mGatewayConnection.isQuitting());
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testUnwantedNetworkAgentWithDisconnectedNetworkAgent() throws Exception {
+ final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
+
+ mGatewayConnection.setNetworkAgent(null);
+ unwantedCallback.accept(mNetworkAgent);
+ mTestLooper.dispatchAll();
+
+ // Verify that the call was ignored; the state machine is still running, and the state has
+ // not changed.
+ assertFalse(mGatewayConnection.isQuitting());
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testUnwantedNetworkAgentWithNewNetworkAgent() throws Exception {
+ final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
+ final VcnNetworkAgent testAgent = mock(VcnNetworkAgent.class);
+
+ mGatewayConnection.setNetworkAgent(testAgent);
+ unwantedCallback.accept(mNetworkAgent);
+ mTestLooper.dispatchAll();
+
+ assertFalse(mGatewayConnection.isQuitting());
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ assertEquals(testAgent, mGatewayConnection.getNetworkAgent());
+ }
+
@Test
public void testChildSessionClosedTriggersDisconnect() throws Exception {
// Verify scheduled but not canceled when entering ConnectedState
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index c5ed8f6..dc73be2 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -18,6 +18,7 @@
import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
import static org.junit.Assert.assertEquals;
@@ -44,7 +45,6 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
-import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.IkeSessionCallback;
@@ -90,12 +90,18 @@
protected static final int TEST_SUB_ID = 5;
protected static final long ELAPSED_REAL_TIME = 123456789L;
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
new UnderlyingNetworkRecord(
new Network(0),
new NetworkCapabilities(),
new LinkProperties(),
false /* blocked */);
+
+ static {
+ TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500);
+ }
+
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
new UnderlyingNetworkRecord(
new Network(1),
@@ -103,6 +109,10 @@
new LinkProperties(),
false /* blocked */);
+ static {
+ TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460);
+ }
+
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
new TelephonySubscriptionSnapshot(
Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP);
@@ -278,8 +288,8 @@
protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
@NonNull State expectedState) {
- // Set a NetworkAgent, and expect it to be unregistered and cleared
- final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class);
+ // Set a VcnNetworkAgent, and expect it to be unregistered and cleared
+ final VcnNetworkAgent mockNetworkAgent = mock(VcnNetworkAgent.class);
mGatewayConnection.setNetworkAgent(mockNetworkAgent);
// SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
diff --git a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
new file mode 100644
index 0000000..29511f7
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.vcn.util;
+
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
+import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
+
+import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
+import static com.android.server.vcn.util.MtuUtils.getMtu;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import static java.util.Collections.emptyList;
+
+import android.net.ipsec.ike.ChildSaProposal;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MtuUtilsTest {
+ @Test
+ public void testUnderlyingMtuZero() {
+ assertEquals(
+ IPV6_MIN_MTU, getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */));
+ }
+
+ @Test
+ public void testClampsToMaxMtu() {
+ assertEquals(0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */));
+ }
+
+ @Test
+ public void testNormalModeAlgorithmLessThanUnderlyingMtu() {
+ final List<ChildSaProposal> saProposals =
+ Arrays.asList(
+ new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)
+ .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
+ .build());
+
+ final int actualMtu =
+ getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
+ assertTrue(ETHER_MTU > actualMtu);
+ }
+
+ @Test
+ public void testCombinedModeAlgorithmLessThanUnderlyingMtu() {
+ final List<ChildSaProposal> saProposals =
+ Arrays.asList(
+ new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256)
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256)
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256)
+ .build());
+
+ final int actualMtu =
+ getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
+ assertTrue(ETHER_MTU > actualMtu);
+ }
+}
diff --git a/tools/hiddenapi/checksorted_sha.sh b/tools/hiddenapi/checksorted_sha.sh
index ceb705f..451fed6 100755
--- a/tools/hiddenapi/checksorted_sha.sh
+++ b/tools/hiddenapi/checksorted_sha.sh
@@ -1,7 +1,7 @@
#!/bin/bash
set -e
LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
-git show --name-only --pretty=format: $1 | grep "config/hiddenapi-.*txt" | while read file; do
+git show --name-only --pretty=format: $1 | grep "boot/hiddenapi/hiddenapi-.*txt" | while read file; do
diff <(git show $1:$file) <(git show $1:$file | $LOCAL_DIR/sort_api.sh ) || {
echo -e "\e[1m\e[31m$file $1 is not sorted or contains duplicates. To sort it correctly:\e[0m"
echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $2/frameworks/base/$file\e[0m"
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 2924e01..822aba4 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -48,7 +48,7 @@
PACKAGES=$(for t in $TEAMS; do echo $(eval echo \${${t}_PACKAGES}); done)
RE=$(echo ${PACKAGES} | sed "s/ /|/g")
EXIT_CODE=0
-for file in $(git show --name-only --pretty=format: $SHA | grep "config/hiddenapi-.*txt"); do
+for file in $(git show --name-only --pretty=format: $SHA | grep "boot/hiddenapi/hiddenapi-.*txt"); do
ENTRIES=$(grep -E "^\+L(${RE})/" <(git diff ${SHA}~1 ${SHA} $file) | sed "s|^\+||" || echo)
if [[ -n "${ENTRIES}" ]]; then
echo -e "\e[1m\e[31m$file $SHA contains the following entries\e[0m"