summaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java7
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java51
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java7
-rw-r--r--services/core/java/com/android/server/SystemService.java3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java8
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java17
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java2
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java4
-rw-r--r--services/core/java/com/android/server/compat/OverrideValidatorImpl.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java17
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java31
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java8
-rw-r--r--services/core/java/com/android/server/notification/BubbleExtractor.java27
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java5
-rw-r--r--services/core/java/com/android/server/notification/ShortcutHelper.java42
-rw-r--r--services/core/java/com/android/server/om/IdmapDaemon.java9
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java40
-rw-r--r--services/core/java/com/android/server/om/OverlayActorEnforcer.java4
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java15
-rw-r--r--services/core/java/com/android/server/om/OverlayableInfoCallback.java20
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java10
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java31
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java57
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java44
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java44
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java48
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java23
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java30
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java234
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java31
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java39
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java6
-rw-r--r--services/core/java/com/android/server/wm/FixedRotationAnimationController.java166
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java9
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java54
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java15
-rw-r--r--services/core/java/com/android/server/wm/ShellRoot.java1
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java20
-rw-r--r--services/incremental/BinderIncrementalService.cpp16
-rw-r--r--services/incremental/BinderIncrementalService.h10
-rw-r--r--services/incremental/IncrementalService.cpp66
-rw-r--r--services/incremental/IncrementalService.h29
-rw-r--r--services/incremental/ServiceWrappers.cpp4
-rw-r--r--services/incremental/ServiceWrappers.h4
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp117
-rw-r--r--services/people/java/com/android/server/people/data/ConversationInfo.java11
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java12
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java31
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java82
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java137
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java442
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java79
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java51
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java14
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java21
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java23
70 files changed, 1842 insertions, 723 deletions
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 103151dcdda5..26e85beba58b 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -51,7 +51,7 @@ import java.util.function.Consumer;
*/
public class AppPredictionPerUserService extends
AbstractPerUserSystemService<AppPredictionPerUserService, AppPredictionManagerService>
- implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
+ implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
private static final String TAG = AppPredictionPerUserService.class.getSimpleName();
private static final String PREDICT_USING_PEOPLE_SERVICE_PREFIX =
@@ -114,8 +114,11 @@ public class AppPredictionPerUserService extends
public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
@NonNull AppPredictionSessionId sessionId) {
if (!mSessionInfos.containsKey(sessionId)) {
+ // TODO(b/157500121): remove below forceUsingPeopleService logic after testing
+ // PeopleService for 2 weeks on Droidfood.
+ final boolean forceUsingPeopleService = context.getUiSurface().equals("share");
mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
- DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
+ forceUsingPeopleService || DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false),
this::removeAppPredictionSessionInfo));
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7c61ba2e7adb..1e9a9d85e06a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3102,30 +3102,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void notifyDataStallSuspected(DataStallReportParcelable p, int netId) {
+ log("Data stall detected with methods: " + p.detectionMethod);
+
final PersistableBundle extras = new PersistableBundle();
- switch (p.detectionMethod) {
- case DETECTION_METHOD_DNS_EVENTS:
- extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts);
- break;
- case DETECTION_METHOD_TCP_METRICS:
- extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate);
- extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS,
- p.tcpMetricsCollectionPeriodMillis);
- break;
- default:
- // TODO(b/156294356): update for new data stall detection methods
- log("Unknown data stall detection method, ignoring: " + p.detectionMethod);
- return;
+ int detectionMethod = 0;
+ if (hasDataStallDetectionMethod(p, DETECTION_METHOD_DNS_EVENTS)) {
+ extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts);
+ detectionMethod |= DETECTION_METHOD_DNS_EVENTS;
+ }
+ if (hasDataStallDetectionMethod(p, DETECTION_METHOD_TCP_METRICS)) {
+ extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate);
+ extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS,
+ p.tcpMetricsCollectionPeriodMillis);
+ detectionMethod |= DETECTION_METHOD_TCP_METRICS;
}
- notifyDataStallSuspected(p.detectionMethod, netId, p.timestampMillis, extras);
- }
-
- private void notifyDataStallSuspected(int detectionMethod, int netId, long timestampMillis,
- @NonNull PersistableBundle extras) {
final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, detectionMethod, netId,
- timestampMillis);
+ p.timestampMillis);
msg.setData(new Bundle(extras));
// NetworkStateTrackerHandler currently doesn't take any actions based on data
@@ -3134,6 +3128,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
mConnectivityDiagnosticsHandler.sendMessage(msg);
}
+ private boolean hasDataStallDetectionMethod(DataStallReportParcelable p, int detectionMethod) {
+ return (p.detectionMethod & detectionMethod) != 0;
+ }
+
private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
return isPrivateDnsValidationRequired(nai.networkCapabilities);
}
@@ -8189,6 +8187,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
+ "creators");
}
- notifyDataStallSuspected(detectionMethod, network.netId, timestampMillis, extras);
+ final DataStallReportParcelable p = new DataStallReportParcelable();
+ p.timestampMillis = timestampMillis;
+ p.detectionMethod = detectionMethod;
+
+ if (hasDataStallDetectionMethod(p, DETECTION_METHOD_DNS_EVENTS)) {
+ p.dnsConsecutiveTimeouts = extras.getInt(KEY_DNS_CONSECUTIVE_TIMEOUTS);
+ }
+ if (hasDataStallDetectionMethod(p, DETECTION_METHOD_TCP_METRICS)) {
+ p.tcpPacketFailRate = extras.getInt(KEY_TCP_PACKET_FAIL_RATE);
+ p.tcpMetricsCollectionPeriodMillis = extras.getInt(
+ KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS);
+ }
+
+ notifyDataStallSuspected(p, network.netId);
}
}
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index e77458cc955a..e303f0d00214 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -177,9 +177,6 @@ public class PackageWatchdog {
// 0 if no prune is scheduled.
@GuardedBy("mLock")
private long mUptimeAtLastStateSync;
- // If true, sync explicit health check packages with the ExplicitHealthCheckController.
- @GuardedBy("mLock")
- private boolean mSyncRequired = false;
@FunctionalInterface
@VisibleForTesting
@@ -255,7 +252,6 @@ public class PackageWatchdog {
*/
public void registerHealthObserver(PackageHealthObserver observer) {
synchronized (mLock) {
- mSyncRequired = true;
ObserverInternal internalObserver = mAllObservers.get(observer.getName());
if (internalObserver != null) {
internalObserver.registeredObserver = observer;
@@ -642,7 +638,7 @@ public class PackageWatchdog {
synchronized (mLock) {
if (mIsPackagesReady) {
Set<String> packages = getPackagesPendingHealthChecksLocked();
- if (!packages.equals(mRequestedHealthCheckPackages) || mSyncRequired) {
+ if (!packages.equals(mRequestedHealthCheckPackages) || packages.isEmpty()) {
syncRequired = true;
mRequestedHealthCheckPackages = packages;
}
@@ -654,7 +650,6 @@ public class PackageWatchdog {
Slog.i(TAG, "Syncing health check requests for packages: "
+ mRequestedHealthCheckPackages);
mHealthCheckController.syncRequests(mRequestedHealthCheckPackages);
- mSyncRequired = false;
}
}
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index e5c05408f628..45d53a14d1e9 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -68,8 +68,7 @@ import java.util.List;
public abstract class SystemService {
/** @hide */
- // TODO(b/133242016) STOPSHIP: change to false before R ships
- protected static final boolean DEBUG_USER = true;
+ protected static final boolean DEBUG_USER = false;
/*
* The earliest boot phase the system send to system services on boot.
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cca604655f3d..ec12aebc37f6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4914,8 +4914,13 @@ public final class ActiveServices {
// TODO: remove this toast after feature development is done
void showWhileInUseDebugToastLocked(int uid, int op, int mode) {
- for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+ final UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(uid);
+ if (uidRec == null) {
+ return;
+ }
+
+ for (int i = uidRec.procRecords.size() - 1; i >= 0; i--) {
+ ProcessRecord pr = uidRec.procRecords.valueAt(i);
if (pr.uid != uid) {
continue;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 671733b7cb7a..7ef527cb7d84 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11112,6 +11112,14 @@ public class ActivityManagerService extends IActivityManager.Stub
}
pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid);
pw.print(": "); pw.println(uidRec);
+ pw.print(" curProcState="); pw.print(uidRec.mCurProcState);
+ pw.print(" curCapability=");
+ ActivityManager.printCapabilitiesFull(pw, uidRec.curCapability);
+ pw.println();
+ for (int j = uidRec.procRecords.size() - 1; j >= 0; j--) {
+ pw.print(" proc=");
+ pw.println(uidRec.procRecords.valueAt(j));
+ }
}
return printed;
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index f7a158a885c6..a81590c8c022 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -324,8 +324,21 @@ public final class OomAdjuster {
boolean success = applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
if (uidRec != null) {
- updateAppUidRecLocked(app);
- // If this proc state is changed, need to update its uid record here
+ // After uidRec.reset() above, for UidRecord that has multiple processes (ProcessRecord)
+ // , We need to apply all ProcessRecord into UidRecord.
+ final ArraySet<ProcessRecord> procRecords = app.uidRecord.procRecords;
+ for (int i = procRecords.size() - 1; i >= 0; i--) {
+ final ProcessRecord pr = procRecords.valueAt(i);
+ if (!pr.killedByAm && pr.thread != null) {
+ if (pr.isolated && pr.numberOfRunningServices() <= 0
+ && pr.isolatedEntryPoint == null) {
+ // No op.
+ } else {
+ // Keeping this process, update its uid.
+ updateAppUidRecLocked(pr);
+ }
+ }
+ }
if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
&& (uidRec.setProcState != uidRec.getCurProcState()
|| uidRec.setCapability != uidRec.curCapability
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 108fb7dff2cd..9f2a77c05d2b 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2808,6 +2808,7 @@ public final class ProcessList {
uidRec.curCapability);
}
proc.uidRecord = uidRec;
+ uidRec.procRecords.add(proc);
// Reset render thread tid if it was already set, so new process can set it again.
proc.renderThreadTid = 0;
@@ -2901,6 +2902,7 @@ public final class ProcessList {
}
if (old != null && old.uidRecord != null) {
old.uidRecord.numProcs--;
+ old.uidRecord.procRecords.remove(old);
if (old.uidRecord.numProcs == 0) {
// No more processes using this uid, tell clients it is gone.
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index acf8b2e84821..c84ccb298bef 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -21,6 +21,7 @@ import android.app.ActivityManager;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
@@ -32,7 +33,7 @@ import com.android.internal.annotations.GuardedBy;
*/
public final class UidRecord {
final int uid;
- private int mCurProcState;
+ int mCurProcState;
int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
int curCapability;
int setCapability;
@@ -44,6 +45,7 @@ public final class UidRecord {
boolean idle;
boolean setIdle;
int numProcs;
+ ArraySet<ProcessRecord> procRecords = new ArraySet<>();
/**
* Sequence number associated with the {@link #mCurProcState}. This is incremented using
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index f5d6e5ac46e5..08d266478f4b 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -89,7 +89,7 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
}
// Only allow to opt-in for a targetSdk gated change.
- if (disabled || applicationInfo.targetSdkVersion < minTargetSdk) {
+ if (disabled || appTargetSdk <= minTargetSdk) {
return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
}
return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 34d0bed9a802..3091a7178377 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -198,6 +198,9 @@ public class Nat464Xlat extends BaseNetworkObserver {
if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) {
stopPrefixDiscovery();
}
+ if (!mPrefixDiscoveryRunning) {
+ setPrefix64(mNat64PrefixInUse);
+ }
}
/**
@@ -221,6 +224,10 @@ public class Nat464Xlat extends BaseNetworkObserver {
mIface = null;
mBaseIface = null;
+ if (!mPrefixDiscoveryRunning) {
+ setPrefix64(null);
+ }
+
if (isPrefixDiscoveryNeeded()) {
if (!mPrefixDiscoveryRunning) {
startPrefixDiscovery();
@@ -308,6 +315,16 @@ public class Nat464Xlat extends BaseNetworkObserver {
return requiresClat(mNetwork) && mNat64PrefixFromRa == null;
}
+ private void setPrefix64(IpPrefix prefix) {
+ final String prefixString = (prefix != null) ? prefix.toString() : "";
+ try {
+ mDnsResolver.setPrefix64(getNetId(), prefixString);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Slog.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
+ + prefix + ": " + e);
+ }
+ }
+
private void maybeHandleNat64PrefixChange() {
final IpPrefix newPrefix = selectNat64Prefix();
if (!Objects.equals(mNat64PrefixInUse, newPrefix)) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index f3c787462d61..a33817c0bf24 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -65,6 +65,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkProvider;
+import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.VpnManager;
@@ -2225,12 +2226,27 @@ public class Vpn {
@Override
public void run() {
- // Explicitly use only the network that ConnectivityService thinks is the "best." In
- // other words, only ever use the currently selected default network. This does mean
- // that in both onLost() and onConnected(), any old sessions MUST be torn down. This
- // does NOT include VPNs.
+ // Unless the profile is restricted to test networks, explicitly use only the network
+ // that ConnectivityService thinks is the "best." In other words, only ever use the
+ // currently selected default network. This does mean that in both onLost() and
+ // onConnected(), any old sessions MUST be torn down. This does NOT include VPNs.
+ //
+ // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
+ // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
+ // this is considered safe.
final ConnectivityManager cm = ConnectivityManager.from(mContext);
- cm.requestNetwork(cm.getDefaultRequest(), mNetworkCallback);
+ final NetworkRequest req;
+
+ if (mProfile.isRestrictedToTestNetworks()) {
+ req = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+ .build();
+ } else {
+ req = cm.getDefaultRequest();
+ }
+
+ cm.requestNetwork(req, mNetworkCallback);
}
private boolean isActiveNetwork(@Nullable Network network) {
@@ -2868,6 +2884,11 @@ public class Vpn {
verifyCallingUidAndPackage(packageName);
enforceNotRestrictedUser();
+ if (profile.isRestrictedToTestNetworks) {
+ mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS,
+ "Test-mode profiles require the MANAGE_TEST_NETWORKS permission");
+ }
+
final byte[] encodedProfile = profile.encode();
if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) {
throw new IllegalArgumentException("Profile too big");
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index b9cd43d0803d..787f7f398fcb 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -28,7 +28,6 @@ import android.util.Pair;
import android.util.Slog;
import android.util.Spline;
-import com.android.internal.BrightnessSynchronizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.server.display.utils.Plog;
@@ -347,10 +346,11 @@ public abstract class BrightnessMappingStrategy {
}
}
+ // Normalize entire brightness range to 0 - 1.
protected static float normalizeAbsoluteBrightness(int brightness) {
- return BrightnessSynchronizer.brightnessIntToFloat(brightness,
- PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON,
- PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX);
+ brightness = MathUtils.constrain(brightness,
+ PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
+ return (float) brightness / PowerManager.BRIGHTNESS_ON;
}
private Pair<float[], float[]> insertControlPoint(
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
index d7d413c2ffb0..0fa339f65cdb 100644
--- a/services/core/java/com/android/server/notification/BubbleExtractor.java
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -75,9 +75,19 @@ public class BubbleExtractor implements NotificationSignalExtractor {
mConfig.getBubblePreference(
record.getSbn().getPackageName(), record.getSbn().getUid());
NotificationChannel recordChannel = record.getChannel();
+ boolean canPresentAsBubble = canPresentAsBubble(record)
+ && !mActivityManager.isLowRamDevice()
+ && record.isConversation()
+ && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0;
- if (!mConfig.bubblesEnabled() || bubblePreference == BUBBLE_PREFERENCE_NONE) {
+ if (!mConfig.bubblesEnabled()
+ || bubblePreference == BUBBLE_PREFERENCE_NONE
+ || !canPresentAsBubble) {
record.setAllowBubble(false);
+ if (!canPresentAsBubble) {
+ // clear out bubble metadata since it can't be used
+ record.getNotification().setBubbleMetadata(null);
+ }
} else if (recordChannel == null) {
// the app is allowed but there's no channel to check
record.setAllowBubble(true);
@@ -86,14 +96,15 @@ public class BubbleExtractor implements NotificationSignalExtractor {
} else if (bubblePreference == BUBBLE_PREFERENCE_SELECTED) {
record.setAllowBubble(recordChannel.canBubble());
}
+ if (DBG) {
+ Slog.d(TAG, "record: " + record.getKey()
+ + " appPref: " + bubblePreference
+ + " canBubble: " + record.canBubble()
+ + " canPresentAsBubble: " + canPresentAsBubble
+ + " flagRemoved: " + record.isFlagBubbleRemoved());
+ }
- final boolean fulfillsPolicy = record.canBubble()
- && record.isConversation()
- && !mActivityManager.isLowRamDevice()
- && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0;
- final boolean applyFlag = fulfillsPolicy
- && canPresentAsBubble(record)
- && !record.isFlagBubbleRemoved();
+ final boolean applyFlag = record.canBubble() && !record.isFlagBubbleRemoved();
if (applyFlag) {
record.getNotification().flags |= FLAG_BUBBLE;
} else {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 9d56d817440b..77b030f9ed0d 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -85,7 +85,8 @@ public class PreferencesHelper implements RankingConfig {
private static final int XML_VERSION = 2;
/** What version to check to do the upgrade for bubbles. */
private static final int XML_VERSION_BUBBLES_UPGRADE = 1;
- private static final int UNKNOWN_UID = UserHandle.USER_NULL;
+ @VisibleForTesting
+ static final int UNKNOWN_UID = UserHandle.USER_NULL;
private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
@VisibleForTesting
@@ -224,7 +225,7 @@ public class PreferencesHelper implements RankingConfig {
}
boolean skipWarningLogged = false;
boolean hasSAWPermission = false;
- if (upgradeForBubbles) {
+ if (upgradeForBubbles && uid != UNKNOWN_UID) {
hasSAWPermission = mAppOps.noteOpNoThrow(
OP_SYSTEM_ALERT_WINDOW, uid, name, null,
"check-notif-bubble") == AppOpsManager.MODE_ALLOWED;
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index e79d33fa5f7a..ee02e3fa8140 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -28,6 +28,7 @@ import android.content.pm.ShortcutServiceInternal;
import android.os.Binder;
import android.os.Handler;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -111,6 +112,15 @@ public class ShortcutHelper {
}
if (!foundShortcut) {
bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId));
+ shortcutBubbles.remove(shortcutId);
+ if (shortcutBubbles.isEmpty()) {
+ mActiveShortcutBubbles.remove(packageName);
+ if (mLauncherAppsCallbackRegistered
+ && mActiveShortcutBubbles.isEmpty()) {
+ mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
+ mLauncherAppsCallbackRegistered = false;
+ }
+ }
}
}
}
@@ -198,7 +208,7 @@ public class ShortcutHelper {
if (shortcutInfo.isLongLived() && !shortcutInfo.isCached()) {
mShortcutServiceInternal.cacheShortcuts(user.getIdentifier(), "android",
shortcutInfo.getPackage(), Collections.singletonList(shortcutInfo.getId()),
- shortcutInfo.getUserId());
+ shortcutInfo.getUserId(), ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
}
}
@@ -209,15 +219,16 @@ public class ShortcutHelper {
* @param removedNotification true if this notification is being removed
* @param handler handler to register the callback with
*/
- void maybeListenForShortcutChangesForBubbles(NotificationRecord r, boolean removedNotification,
+ void maybeListenForShortcutChangesForBubbles(NotificationRecord r,
+ boolean removedNotification,
Handler handler) {
final String shortcutId = r.getNotification().getBubbleMetadata() != null
? r.getNotification().getBubbleMetadata().getShortcutId()
: null;
- if (shortcutId == null) {
- return;
- }
- if (r.getNotification().isBubbleNotification() && !removedNotification) {
+ if (!removedNotification
+ && !TextUtils.isEmpty(shortcutId)
+ && r.getShortcutInfo() != null
+ && r.getShortcutInfo().getId().equals(shortcutId)) {
// Must track shortcut based bubbles in case the shortcut is removed
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
r.getSbn().getPackageName());
@@ -235,10 +246,21 @@ public class ShortcutHelper {
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
r.getSbn().getPackageName());
if (packageBubbles != null) {
- packageBubbles.remove(shortcutId);
- }
- if (packageBubbles != null && packageBubbles.isEmpty()) {
- mActiveShortcutBubbles.remove(r.getSbn().getPackageName());
+ if (!TextUtils.isEmpty(shortcutId)) {
+ packageBubbles.remove(shortcutId);
+ } else {
+ // Check if there was a matching entry
+ for (String pkgShortcutId : packageBubbles.keySet()) {
+ String entryKey = packageBubbles.get(pkgShortcutId);
+ if (r.getKey().equals(entryKey)) {
+ // No longer has shortcut id so remove it
+ packageBubbles.remove(pkgShortcutId);
+ }
+ }
+ }
+ if (packageBubbles.isEmpty()) {
+ mActiveShortcutBubbles.remove(r.getSbn().getPackageName());
+ }
}
if (mLauncherAppsCallbackRegistered && mActiveShortcutBubbles.isEmpty()) {
mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
index 910ed44df0f8..19fa9204935d 100644
--- a/services/core/java/com/android/server/om/IdmapDaemon.java
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -30,6 +30,7 @@ import android.util.Slog;
import com.android.server.FgThread;
+import java.io.File;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -124,9 +125,13 @@ class IdmapDaemon {
}
}
- String getIdmapPath(String overlayPath, int userId) throws TimeoutException, RemoteException {
+ boolean idmapExists(String overlayPath, int userId) {
try (Connection c = connect()) {
- return mService.getIdmapPath(overlayPath, userId);
+ return new File(mService.getIdmapPath(overlayPath, userId)).isFile();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "failed to check if idmap exists for " + overlayPath + ": "
+ + e.getMessage());
+ return false;
}
}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 90c85ada9def..735d66983520 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -27,10 +27,10 @@ import android.content.pm.PackageInfo;
import android.os.Build.VERSION_CODES;
import android.os.OverlayablePolicy;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.util.Slog;
-import java.io.File;
+import com.android.internal.util.ArrayUtils;
+
import java.io.IOException;
/**
@@ -55,12 +55,16 @@ class IdmapManager {
VENDOR_IS_Q_OR_LATER = isQOrLater;
}
- private final OverlayableInfoCallback mOverlayableCallback;
private final IdmapDaemon mIdmapDaemon;
+ private final OverlayableInfoCallback mOverlayableCallback;
+ private final String mOverlayableConfigurator;
+ private final String[] mOverlayableConfiguratorTargets;
- IdmapManager(final OverlayableInfoCallback verifyCallback) {
+ IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) {
mOverlayableCallback = verifyCallback;
- mIdmapDaemon = IdmapDaemon.getInstance();
+ mIdmapDaemon = idmapDaemon;
+ mOverlayableConfigurator = verifyCallback.getOverlayableConfigurator();
+ mOverlayableConfiguratorTargets = verifyCallback.getOverlayableConfiguratorTargets() ;
}
/**
@@ -103,23 +107,11 @@ class IdmapManager {
}
boolean idmapExists(@NonNull final OverlayInfo oi) {
- return new File(getIdmapPath(oi.baseCodePath, oi.userId)).isFile();
+ return mIdmapDaemon.idmapExists(oi.baseCodePath, oi.userId);
}
boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
- return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath(), userId))
- .isFile();
- }
-
- private @NonNull String getIdmapPath(@NonNull final String overlayPackagePath,
- final int userId) {
- try {
- return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
- } catch (Exception e) {
- Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
- + e.getMessage());
- return "";
- }
+ return mIdmapDaemon.idmapExists(overlayPackage.applicationInfo.getBaseCodePath(), userId);
}
/**
@@ -198,9 +190,17 @@ class IdmapManager {
String targetOverlayableName = overlayPackage.targetOverlayableName;
if (targetOverlayableName != null) {
try {
+ if (!mOverlayableConfigurator.isEmpty()
+ && ArrayUtils.contains(mOverlayableConfiguratorTargets,
+ targetPackage.packageName)
+ && mOverlayableCallback.signaturesMatching(mOverlayableConfigurator,
+ overlayPackage.packageName, userId)) {
+ return true;
+ }
+
OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget(
targetPackage.packageName, targetOverlayableName, userId);
- if (overlayableInfo != null) {
+ if (overlayableInfo != null && overlayableInfo.actor != null) {
String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first;
if (mOverlayableCallback.signaturesMatching(actorPackageName,
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index ef6655dd224e..2bc34998785b 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -50,8 +50,8 @@ public class OverlayActorEnforcer {
/**
* @return nullable actor result with {@link ActorState} failure status
*/
- static Pair<String, ActorState> getPackageNameForActor(String actorUriString,
- Map<String, Map<String, String>> namedActors) {
+ static Pair<String, ActorState> getPackageNameForActor(@NonNull String actorUriString,
+ @NonNull Map<String, Map<String, String>> namedActors) {
Uri actorUri = Uri.parse(actorUriString);
String actorScheme = actorUri.getScheme();
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 6a8e465529d7..086ab8183254 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -45,6 +45,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.ApkAssets;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -62,6 +63,7 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.R;
import com.android.internal.content.om.OverlayConfig;
import com.android.server.FgThread;
import com.android.server.IoThread;
@@ -246,7 +248,7 @@ public final class OverlayManagerService extends SystemService {
new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
mPackageManager = new PackageManagerHelperImpl(context);
mUserManager = UserManagerService.getInstance();
- IdmapManager im = new IdmapManager(mPackageManager);
+ IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager);
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
@@ -1119,6 +1121,17 @@ public final class OverlayManagerService extends SystemService {
}
@Override
+ public String getOverlayableConfigurator() {
+ return Resources.getSystem().getString(R.string.config_overlayableConfigurator);
+ }
+
+ @Override
+ public String[] getOverlayableConfiguratorTargets() {
+ return Resources.getSystem().getStringArray(
+ R.array.config_overlayableConfiguratorTargets);
+ }
+
+ @Override
public List<PackageInfo> getOverlayPackages(final int userId) {
final List<PackageInfo> overlays = mPackageManagerInternal.getOverlayPackages(userId);
for (final PackageInfo info : overlays) {
diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
index 5066ecdd6316..41c341adf1bc 100644
--- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java
+++ b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
@@ -80,4 +80,24 @@ public interface OverlayableInfoCallback {
* in the system returns {@link PackageManager#SIGNATURE_MATCH}
*/
boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+
+ /**
+ * Retrieves the package name that is recognized as an actor for the packages specified by
+ * {@link #getOverlayableConfiguratorTargets()}.
+ */
+ @NonNull
+ default String getOverlayableConfigurator() {
+ return "";
+ }
+
+ /**
+ * Retrieves the target packages that recognize the {@link #getOverlayableConfigurator} as an
+ * actor for its overlayable declarations. Overlays targeting one of the specified targets that
+ * are signed with the same signature as the overlayable configurator will be granted the
+ * "actor" policy.
+ */
+ @NonNull
+ default String[] getOverlayableConfiguratorTargets() {
+ return new String[0];
+ }
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 830388d8f2ac..4b6ee71803a7 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -446,11 +446,6 @@ public class AppsFilter {
}
}
- if (!newPkgSetting.pkg.getProtectedBroadcasts().isEmpty()) {
- mProtectedBroadcasts.addAll(newPkgSetting.pkg.getProtectedBroadcasts());
- recomputeComponentVisibility(existingSettings, newPkgSetting.pkg.getPackageName());
- }
-
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
try {
final AndroidPackage newPkg = newPkgSetting.pkg;
@@ -459,6 +454,11 @@ public class AppsFilter {
return;
}
+ if (!newPkg.getProtectedBroadcasts().isEmpty()) {
+ mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts());
+ recomputeComponentVisibility(existingSettings, newPkg.getPackageName());
+ }
+
final boolean newIsForceQueryable =
mForceQueryable.contains(newPkgSetting.appId)
/* shared user that is already force queryable */
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c6d08c36631a..5bbe49088c02 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -18,6 +18,8 @@ package com.android.server.pm;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS;
+import static android.content.pm.LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -78,6 +80,7 @@ import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -780,26 +783,28 @@ public class LauncherAppsService extends SystemService {
@Override
public void cacheShortcuts(String callingPackage, String packageName, List<String> ids,
- UserHandle targetUser) {
+ UserHandle targetUser, int cacheFlags) {
ensureStrictAccessShortcutsPermission(callingPackage);
if (!canAccessProfile(targetUser.getIdentifier(), "Cannot cache shortcuts")) {
return;
}
- mShortcutServiceInternal.cacheShortcuts(getCallingUserId(),
- callingPackage, packageName, ids, targetUser.getIdentifier());
+ mShortcutServiceInternal.cacheShortcuts(
+ getCallingUserId(), callingPackage, packageName, ids,
+ targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags));
}
@Override
public void uncacheShortcuts(String callingPackage, String packageName, List<String> ids,
- UserHandle targetUser) {
+ UserHandle targetUser, int cacheFlags) {
ensureStrictAccessShortcutsPermission(callingPackage);
if (!canAccessProfile(targetUser.getIdentifier(), "Cannot uncache shortcuts")) {
return;
}
- mShortcutServiceInternal.uncacheShortcuts(getCallingUserId(),
- callingPackage, packageName, ids, targetUser.getIdentifier());
+ mShortcutServiceInternal.uncacheShortcuts(
+ getCallingUserId(), callingPackage, packageName, ids,
+ targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags));
}
@Override
@@ -1058,6 +1063,18 @@ public class LauncherAppsService extends SystemService {
user.getIdentifier(), debugMsg, false);
}
+ private int toShortcutsCacheFlags(int cacheFlags) {
+ int ret = 0;
+ if (cacheFlags == FLAG_CACHE_NOTIFICATION_SHORTCUTS) {
+ ret = ShortcutInfo.FLAG_CACHED_NOTIFICATIONS;
+ } else if (cacheFlags == FLAG_CACHE_BUBBLE_SHORTCUTS) {
+ ret = ShortcutInfo.FLAG_CACHED_BUBBLES;
+ }
+ Preconditions.checkArgumentPositive(ret, "Invalid cache owner");
+
+ return ret;
+ }
+
@VisibleForTesting
void postToPackageMonitorHandler(Runnable r) {
mCallbackHandler.post(r);
@@ -1154,7 +1171,7 @@ public class LauncherAppsService extends SystemService {
final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0)
| (matchPinned ? ShortcutInfo.FLAG_PINNED : 0)
| (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0)
- | (matchCached ? ShortcutInfo.FLAG_CACHED : 0);
+ | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0);
for (int i = 0; i < shortcuts.size(); i++) {
final ShortcutInfo si = shortcuts.get(i);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index f8278de1531d..7ab05c4f762c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -105,8 +105,10 @@ import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.incremental.IStorageHealthListener;
import android.os.incremental.IncrementalFileStorages;
import android.os.incremental.IncrementalManager;
+import android.os.incremental.StorageHealthCheckParams;
import android.os.storage.StorageManager;
import android.provider.Settings.Secure;
import android.stats.devicepolicy.DevicePolicyEnums;
@@ -231,6 +233,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
+ private static final int INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS = 2000;
+ private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
+ private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
+
// TODO: enforce INSTALL_ALLOW_TEST
// TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -1568,7 +1574,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
dispatchSessionFinished(error, detailMessage, null);
}
- private void onDataLoaderUnrecoverable() {
+ private void onStorageUnhealthy() {
if (TextUtils.isEmpty(mPackageName)) {
// The package has not been installed.
return;
@@ -2745,7 +2751,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final DataLoaderParams params = this.params.dataLoaderParams;
final boolean manualStartAndDestroy = !isIncrementalInstallation();
- final IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() {
+ final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() {
@Override
public void onStatusChanged(int dataLoaderId, int status) {
switch (status) {
@@ -2757,7 +2763,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (mDestroyed || mDataLoaderFinished) {
switch (status) {
case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
- onDataLoaderUnrecoverable();
+ onStorageUnhealthy();
return;
}
return;
@@ -2840,9 +2846,49 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
};
if (!manualStartAndDestroy) {
+ final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
+ healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
+ healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
+ healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
+
+ final boolean systemDataLoader =
+ params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE;
+ final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
+ @Override
+ public void onHealthStatus(int storageId, int status) {
+ if (mDestroyed || mDataLoaderFinished) {
+ // App's installed.
+ switch (status) {
+ case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
+ onStorageUnhealthy();
+ return;
+ }
+ return;
+ }
+
+ switch (status) {
+ case IStorageHealthListener.HEALTH_STATUS_OK:
+ break;
+ case IStorageHealthListener.HEALTH_STATUS_READS_PENDING:
+ case IStorageHealthListener.HEALTH_STATUS_BLOCKED:
+ if (systemDataLoader) {
+ // It's OK for ADB data loader to wait for pages.
+ break;
+ }
+ // fallthrough
+ case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
+ // Even ADB installation can't wait for missing pages for too long.
+ mDataLoaderFinished = true;
+ dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ "Image is missing pages required for installation.");
+ break;
+ }
+ }
+ };
+
try {
mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
- params, listener, addedFiles);
+ params, statusListener, healthCheckParams, healthListener, addedFiles);
return false;
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
@@ -2850,8 +2896,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- if (!dataLoaderManager.bindToDataLoader(
- sessionId, params.getData(), listener)) {
+ if (!dataLoaderManager.bindToDataLoader(sessionId, params.getData(), statusListener)) {
throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failed to initialize data loader");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 395e835b6a2a..aa7a1ad2b47a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -369,6 +369,7 @@ import com.android.server.pm.permission.PermissionsState;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -4406,6 +4407,11 @@ public class PackageManagerService extends IPackageManager.Stub
if (getInstantAppPackageName(callingUid) != null) {
throw new SecurityException("Instant applications don't have access to this method");
}
+ if (!mUserManager.exists(userId)) {
+ throw new SecurityException("User doesn't exist");
+ }
+ mPermissionManager.enforceCrossUserPermission(
+ callingUid, userId, false, false, "checkPackageStartable");
final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -5778,9 +5784,15 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ final int callingUid = Binder.getCallingUid();
+ if (getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ if (!mUserManager.exists(userId)) {
return null;
}
+ mPermissionManager.enforceCrossUserPermission(
+ callingUid, userId, false, false, "getChangedPackages");
synchronized (mLock) {
if (sequenceNumber >= mChangedPackagesSequenceNumber) {
return null;
@@ -8800,9 +8812,23 @@ public class PackageManagerService extends IPackageManager.Stub
private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
- flags = updateFlagsForComponent(flags, userId);
final int callingUid = Binder.getCallingUid();
+ flags = updateFlagsForComponent(flags, userId);
final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
+ boolean checkedGrants = false;
+ if (providerInfo != null) {
+ // Looking for cross-user grants before enforcing the typical cross-users permissions
+ if (userId != UserHandle.getUserId(callingUid)) {
+ final UriGrantsManagerInternal mUgmInternal =
+ LocalServices.getService(UriGrantsManagerInternal.class);
+ checkedGrants =
+ mUgmInternal.checkAuthorityGrants(callingUid, providerInfo, userId, true);
+ }
+ }
+ if (!checkedGrants) {
+ mPermissionManager.enforceCrossUserPermission(
+ callingUid, userId, false, false, "resolveContentProvider");
+ }
if (providerInfo == null) {
return null;
}
@@ -16267,10 +16293,16 @@ public class PackageManagerService extends IPackageManager.Stub
// signing certificate than the existing one, and if so, copy over the new
// details
if (signatureCheckPs.sharedUser != null) {
- if (parsedPackage.getSigningDetails().hasAncestor(
- signatureCheckPs.sharedUser.signatures.mSigningDetails)) {
- signatureCheckPs.sharedUser.signatures.mSigningDetails =
- parsedPackage.getSigningDetails();
+ // Attempt to merge the existing lineage for the shared SigningDetails with
+ // the lineage of the new package; if the shared SigningDetails are not
+ // returned this indicates the new package added new signers to the lineage
+ // and/or changed the capabilities of existing signers in the lineage.
+ SigningDetails sharedSigningDetails =
+ signatureCheckPs.sharedUser.signatures.mSigningDetails;
+ SigningDetails mergedDetails = sharedSigningDetails.mergeLineageWith(
+ signingDetails);
+ if (mergedDetails != sharedSigningDetails) {
+ signatureCheckPs.sharedUser.signatures.mSigningDetails = mergedDetails;
}
if (signatureCheckPs.sharedUser.signaturesChanged == null) {
signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 5c175a6ef847..1fce07b0cbf1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -611,7 +611,6 @@ public class PackageManagerServiceUtils {
final String packageName = pkgSetting.name;
boolean compatMatch = false;
if (pkgSetting.signatures.mSigningDetails.signatures != null) {
-
// Already existing package. Make sure signatures match
boolean match = parsedSignatures.checkCapability(
pkgSetting.signatures.mSigningDetails,
@@ -664,6 +663,13 @@ public class PackageManagerServiceUtils {
|| pkgSetting.getSharedUser().signatures.mSigningDetails.checkCapability(
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
+ // Special case: if the sharedUserId capability check failed it could be due to this
+ // being the only package in the sharedUserId so far and the lineage being updated to
+ // deny the sharedUserId capability of the previous key in the lineage.
+ if (!match && pkgSetting.getSharedUser().packages.size() == 1
+ && pkgSetting.getSharedUser().packages.valueAt(0).name.equals(packageName)) {
+ match = true;
+ }
if (!match && compareCompat) {
match = matchSignaturesCompat(
packageName, pkgSetting.getSharedUser().signatures, parsedSignatures);
@@ -686,6 +692,42 @@ public class PackageManagerServiceUtils {
+ " has no signatures that match those in shared user "
+ pkgSetting.getSharedUser().name + "; ignoring!");
}
+ // It is possible that this package contains a lineage that blocks sharedUserId access
+ // to an already installed package in the sharedUserId signed with a previous key.
+ // Iterate over all of the packages in the sharedUserId and ensure any that are signed
+ // with a key in this package's lineage have the SHARED_USER_ID capability granted.
+ if (parsedSignatures.hasPastSigningCertificates()) {
+ for (PackageSetting shUidPkgSetting : pkgSetting.getSharedUser().packages) {
+ // if the current package in the sharedUserId is the package being updated then
+ // skip this check as the update may revoke the sharedUserId capability from
+ // the key with which this app was previously signed.
+ if (packageName.equals(shUidPkgSetting.name)) {
+ continue;
+ }
+ PackageParser.SigningDetails shUidSigningDetails =
+ shUidPkgSetting.getSigningDetails();
+ // The capability check only needs to be performed against the package if it is
+ // signed with a key that is in the lineage of the package being installed.
+ if (parsedSignatures.hasAncestor(shUidSigningDetails)) {
+ if (!parsedSignatures.checkCapability(shUidSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+ "Package " + packageName
+ + " revoked the sharedUserId capability from the "
+ + "signing key used to sign " + shUidPkgSetting.name);
+ }
+ }
+ }
+ }
+ // If the lineage of this package diverges from the lineage of the sharedUserId then
+ // do not allow the installation to proceed.
+ if (!parsedSignatures.hasCommonAncestor(
+ pkgSetting.getSharedUser().signatures.mSigningDetails)) {
+ throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+ "Package " + packageName + " has a signing lineage "
+ + "that diverges from the lineage of the sharedUserId");
+ }
}
return compatMatch;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 16426072ae78..9e27f65105eb 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -287,7 +287,7 @@ class ShortcutPackage extends ShortcutPackageItem {
if (shortcut != null) {
mShortcutUser.mService.removeIconLocked(shortcut);
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
- | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED);
+ | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL);
}
return shortcut;
}
@@ -323,36 +323,18 @@ class ShortcutPackage extends ShortcutPackageItem {
newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
-
- final boolean replaced;
-
- final boolean wasPinned;
- final boolean wasCached;
-
- if (oldShortcut == null) {
- replaced = false;
- wasPinned = false;
- wasCached = false;
- } else {
+ if (oldShortcut != null) {
// It's an update case.
// Make sure the target is updatable. (i.e. should be mutable.)
oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);
- replaced = true;
-
- wasPinned = oldShortcut.isPinned();
- wasCached = oldShortcut.isCached();
- }
- // If it was originally pinned, the new one should be pinned too.
- if (wasPinned) {
- newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
- }
- if (wasCached) {
- newShortcut.addFlags(ShortcutInfo.FLAG_CACHED);
+ // If it was originally pinned or cached, the new one should be pinned or cached too.
+ newShortcut.addFlags(oldShortcut.getFlags()
+ & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL));
}
forceReplaceShortcutInner(newShortcut);
- return replaced;
+ return oldShortcut != null;
}
/**
@@ -373,9 +355,6 @@ class ShortcutPackage extends ShortcutPackageItem {
changedShortcuts.clear();
final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
- boolean wasPinned = false;
- boolean wasCached = false;
-
boolean deleted = false;
if (oldShortcut == null) {
@@ -408,16 +387,9 @@ class ShortcutPackage extends ShortcutPackageItem {
// Make sure the target is updatable. (i.e. should be mutable.)
oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);
- wasPinned = oldShortcut.isPinned();
- wasCached = oldShortcut.isCached();
- }
-
- // If it was originally pinned or cached, the new one should be pinned or cached too.
- if (wasPinned) {
- newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
- }
- if (wasCached) {
- newShortcut.addFlags(ShortcutInfo.FLAG_CACHED);
+ // If it was originally pinned or cached, the new one should be pinned or cached too.
+ newShortcut.addFlags(oldShortcut.getFlags()
+ & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL));
}
forceReplaceShortcutInner(newShortcut);
@@ -511,7 +483,7 @@ class ShortcutPackage extends ShortcutPackageItem {
public ShortcutInfo deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
if (shortcut != null) {
- shortcut.clearFlags(ShortcutInfo.FLAG_CACHED);
+ shortcut.clearFlags(ShortcutInfo.FLAG_CACHED_ALL);
}
return deleteOrDisableWithId(
shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 3732b479c3a3..3ec139763e80 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2407,7 +2407,7 @@ public class ShortcutService extends IShortcutService.Stub {
final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0)
| (matchPinned ? ShortcutInfo.FLAG_PINNED : 0)
| (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0)
- | (matchCached ? ShortcutInfo.FLAG_CACHED : 0);
+ | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0);
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -3045,17 +3045,17 @@ public class ShortcutService extends IShortcutService.Stub {
@Override
public void cacheShortcuts(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
- @NonNull List<String> shortcutIds, int userId) {
+ @NonNull List<String> shortcutIds, int userId, int cacheFlags) {
updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds,
- userId, /* doCache= */ true);
+ userId, cacheFlags, /* doCache= */ true);
}
@Override
public void uncacheShortcuts(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
- @NonNull List<String> shortcutIds, int userId) {
+ @NonNull List<String> shortcutIds, int userId, int cacheFlags) {
updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds,
- userId, /* doCache= */ false);
+ userId, cacheFlags, /* doCache= */ false);
}
@Override
@@ -3079,10 +3079,12 @@ public class ShortcutService extends IShortcutService.Stub {
private void updateCachedShortcutsInternal(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
- @NonNull List<String> shortcutIds, int userId, boolean doCache) {
+ @NonNull List<String> shortcutIds, int userId, int cacheFlags, boolean doCache) {
// Calling permission must be checked by LauncherAppsImpl.
Preconditions.checkStringNotEmpty(packageName, "packageName");
Objects.requireNonNull(shortcutIds, "shortcutIds");
+ Preconditions.checkState(
+ (cacheFlags & ShortcutInfo.FLAG_CACHED_ALL) != 0, "invalid cacheFlags");
List<ShortcutInfo> changedShortcuts = null;
List<ShortcutInfo> removedShortcuts = null;
@@ -3101,13 +3103,13 @@ public class ShortcutService extends IShortcutService.Stub {
for (int i = 0; i < idSize; i++) {
final String id = Preconditions.checkStringNotEmpty(shortcutIds.get(i));
final ShortcutInfo si = sp.findShortcutById(id);
- if (si == null || doCache == si.isCached()) {
+ if (si == null || doCache == si.hasFlags(cacheFlags)) {
continue;
}
if (doCache) {
if (si.isLongLived()) {
- si.addFlags(ShortcutInfo.FLAG_CACHED);
+ si.addFlags(cacheFlags);
if (changedShortcuts == null) {
changedShortcuts = new ArrayList<>(1);
}
@@ -3118,9 +3120,8 @@ public class ShortcutService extends IShortcutService.Stub {
}
} else {
ShortcutInfo removed = null;
- if (si.isDynamic()) {
- si.clearFlags(ShortcutInfo.FLAG_CACHED);
- } else {
+ si.clearFlags(cacheFlags);
+ if (!si.isDynamic() && !si.isCached()) {
removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
}
if (removed != null) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 29428a27e6da..b0e3ecb6d17b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3507,7 +3507,7 @@ public class UserManagerService extends IUserManager.Stub {
Slog.w(LOG_TAG, "could not start pre-created user " + userId, e);
}
} else {
- dispatchUserAddedIntent(userInfo);
+ dispatchUserAdded(userInfo);
}
} finally {
@@ -3568,7 +3568,7 @@ public class UserManagerService extends IUserManager.Stub {
// Could not read the existing permissions, re-grant them.
mPm.onNewUserCreated(preCreatedUser.id);
}
- dispatchUserAddedIntent(preCreatedUser);
+ dispatchUserAdded(preCreatedUser);
return preCreatedUser;
}
@@ -3600,7 +3600,7 @@ public class UserManagerService extends IUserManager.Stub {
return (now > EPOCH_PLUS_30_YEARS) ? now : 0;
}
- private void dispatchUserAddedIntent(@NonNull UserInfo userInfo) {
+ private void dispatchUserAdded(@NonNull UserInfo userInfo) {
Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
// Also, add the UserHandle for mainline modules which can't use the @hide
@@ -3610,6 +3610,15 @@ public class UserManagerService extends IUserManager.Stub {
android.Manifest.permission.MANAGE_USERS);
MetricsLogger.count(mContext, userInfo.isGuest() ? TRON_GUEST_CREATED
: (userInfo.isDemo() ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1);
+
+ if (!userInfo.isProfile()) {
+ // If the user switch hasn't been explicitly toggled on or off by the user, turn it on.
+ if (android.provider.Settings.Global.getString(mContext.getContentResolver(),
+ android.provider.Settings.Global.USER_SWITCHER_ENABLED) == null) {
+ android.provider.Settings.Global.putInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.USER_SWITCHER_ENABLED, 1);
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 1fec8aa0a3ff..14d043c371e2 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -206,21 +206,9 @@ public class UserRestrictionsUtils {
*/
private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
Sets.newArraySet(
- UserManager.DISALLOW_CONFIG_DATE_TIME,
- UserManager.DISALLOW_CAMERA,
- UserManager.DISALLOW_BLUETOOTH,
- UserManager.DISALLOW_BLUETOOTH_SHARING,
- UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
- UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
- UserManager.DISALLOW_CONFIG_PRIVATE_DNS,
- UserManager.DISALLOW_CONFIG_TETHERING,
- UserManager.DISALLOW_DATA_ROAMING,
- UserManager.DISALLOW_SAFE_BOOT,
- UserManager.DISALLOW_SMS,
- UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_AIRPLANE_MODE,
- UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
- UserManager.DISALLOW_UNMUTE_MICROPHONE
+ UserManager.DISALLOW_CONFIG_DATE_TIME,
+ UserManager.DISALLOW_CONFIG_PRIVATE_DNS
);
/**
@@ -236,7 +224,19 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_CONTENT_SUGGESTIONS,
UserManager.DISALLOW_DEBUGGING_FEATURES,
UserManager.DISALLOW_SHARE_LOCATION,
- UserManager.DISALLOW_OUTGOING_CALLS
+ UserManager.DISALLOW_OUTGOING_CALLS,
+ UserManager.DISALLOW_CAMERA,
+ UserManager.DISALLOW_BLUETOOTH,
+ UserManager.DISALLOW_BLUETOOTH_SHARING,
+ UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
+ UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
+ UserManager.DISALLOW_CONFIG_TETHERING,
+ UserManager.DISALLOW_DATA_ROAMING,
+ UserManager.DISALLOW_SAFE_BOOT,
+ UserManager.DISALLOW_SMS,
+ UserManager.DISALLOW_USB_FILE_TRANSFER,
+ UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
+ UserManager.DISALLOW_UNMUTE_MICROPHONE
);
/**
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 29c1243c299d..0b3254f53324 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -179,6 +179,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.function.BiConsumer;
/**
* SystemService containing PullAtomCallbacks that are registered with statsd.
@@ -325,6 +326,7 @@ public class StatsPullAtomService extends SystemService {
case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG:
case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
+ case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED:
return pullDataBytesTransfer(atomTag, data);
case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER:
return pullBluetoothBytesTransfer(atomTag, data);
@@ -641,11 +643,14 @@ public class StatsPullAtomService extends SystemService {
collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.MOBILE_BYTES_TRANSFER));
mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom(
FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG));
+ mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom(
+ FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED));
registerWifiBytesTransfer();
registerWifiBytesTransferBackground();
registerMobileBytesTransfer();
registerMobileBytesTransferBackground();
+ registerBytesTransferByTagAndMetered();
}
/**
@@ -787,50 +792,94 @@ public class StatsPullAtomService extends SystemService {
private static class NetworkStatsExt {
@NonNull
public final NetworkStats stats;
- public final int transport;
- public final boolean withFgbg;
+ public final int[] transports;
+ public final boolean slicedByFgbg;
+ public final boolean slicedByTag;
+ public final boolean slicedByMetered;
+
+ NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg) {
+ this(stats, transports, slicedByFgbg, /*slicedByTag=*/false, /*slicedByMetered=*/false);
+ }
- NetworkStatsExt(@NonNull NetworkStats stats, int transport, boolean withFgbg) {
+ NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg,
+ boolean slicedByTag, boolean slicedByMetered) {
this.stats = stats;
- this.transport = transport;
- this.withFgbg = withFgbg;
+
+ // Sort transports array so that we can test for equality without considering order.
+ this.transports = Arrays.copyOf(transports, transports.length);
+ Arrays.sort(this.transports);
+
+ this.slicedByFgbg = slicedByFgbg;
+ this.slicedByTag = slicedByTag;
+ this.slicedByMetered = slicedByMetered;
+ }
+
+ public boolean hasSameSlicing(@NonNull NetworkStatsExt other) {
+ return Arrays.equals(transports, other.transports) && slicedByFgbg == other.slicedByFgbg
+ && slicedByTag == other.slicedByTag && slicedByMetered == other.slicedByMetered;
}
}
@NonNull
private List<NetworkStatsExt> collectNetworkStatsSnapshotForAtom(int atomTag) {
+ List<NetworkStatsExt> ret = new ArrayList<>();
switch(atomTag) {
- case FrameworkStatsLog.WIFI_BYTES_TRANSFER:
- return collectUidNetworkStatsSnapshot(TRANSPORT_WIFI, /*withFgbg=*/false);
- case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG:
- return collectUidNetworkStatsSnapshot(TRANSPORT_WIFI, /*withFgbg=*/true);
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
- return collectUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, /*withFgbg=*/false);
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
- return collectUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, /*withFgbg=*/true);
+ case FrameworkStatsLog.WIFI_BYTES_TRANSFER: {
+ final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_WIFI,
+ /*includeTags=*/false);
+ if (stats != null) {
+ ret.add(new NetworkStatsExt(stats.groupedByUid(), new int[] {TRANSPORT_WIFI},
+ /*slicedByFgbg=*/false));
+ }
+ break;
+ }
+ case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
+ final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_WIFI,
+ /*includeTags=*/false);
+ if (stats != null) {
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+ new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
+ }
+ break;
+ }
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER: {
+ final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_CELLULAR,
+ /*includeTags=*/false);
+ if (stats != null) {
+ ret.add(new NetworkStatsExt(stats.groupedByUid(),
+ new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
+ }
+ break;
+ }
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
+ final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_CELLULAR,
+ /*includeTags=*/false);
+ if (stats != null) {
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+ new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
+ }
+ break;
+ }
+ case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: {
+ final NetworkStats wifiStats = getUidNetworkStatsSnapshot(TRANSPORT_WIFI,
+ /*includeTags=*/true);
+ final NetworkStats cellularStats = getUidNetworkStatsSnapshot(TRANSPORT_CELLULAR,
+ /*includeTags=*/true);
+ if (wifiStats != null && cellularStats != null) {
+ final NetworkStats stats = wifiStats.add(cellularStats);
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
+ new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR},
+ /*slicedByFgbg=*/false, /*slicedByTag=*/true,
+ /*slicedByMetered=*/true));
+ }
+ break;
+ }
default:
throw new IllegalArgumentException("Unknown atomTag " + atomTag);
}
- }
-
- // Get a snapshot of Uid NetworkStats. The snapshot contains NetworkStats with its associated
- // information, and wrapped by a list since multiple NetworkStatsExt objects might be collected.
- @NonNull
- private List<NetworkStatsExt> collectUidNetworkStatsSnapshot(int transport, boolean withFgbg) {
- final List<NetworkStatsExt> ret = new ArrayList<>();
- final NetworkTemplate template = (transport == TRANSPORT_CELLULAR
- ? NetworkTemplate.buildTemplateMobileWithRatType(
- /*subscriptionId=*/null, NETWORK_TYPE_ALL)
- : NetworkTemplate.buildTemplateWifiWildcard());
-
- final NetworkStats stats = getUidNetworkStatsSnapshot(template, withFgbg);
- if (stats != null) {
- ret.add(new NetworkStatsExt(stats, transport, withFgbg));
- }
return ret;
}
-
private int pullDataBytesTransfer(
int atomTag, @NonNull List<StatsEvent> pulledData) {
final List<NetworkStatsExt> current = collectNetworkStatsSnapshotForAtom(atomTag);
@@ -842,22 +891,28 @@ public class StatsPullAtomService extends SystemService {
for (final NetworkStatsExt item : current) {
final NetworkStatsExt baseline = CollectionUtils.find(mNetworkStatsBaselines,
- it -> it.withFgbg == item.withFgbg && it.transport == item.transport);
+ it -> it.hasSameSlicing(item));
// No matched baseline indicates error has occurred during initialization stage,
// skip reporting anything since the snapshot is invalid.
if (baseline == null) {
- Slog.e(TAG, "baseline is null for " + atomTag + ", transport="
- + item.transport + " , withFgbg=" + item.withFgbg + ", return.");
+ Slog.e(TAG, "baseline is null for " + atomTag + ", return.");
return StatsManager.PULL_SKIP;
}
- final NetworkStatsExt diff = new NetworkStatsExt(item.stats.subtract(
- baseline.stats).removeEmptyEntries(), item.transport, item.withFgbg);
+ final NetworkStatsExt diff = new NetworkStatsExt(
+ item.stats.subtract(baseline.stats).removeEmptyEntries(), item.transports,
+ item.slicedByFgbg, item.slicedByTag, item.slicedByMetered);
// If no diff, skip.
if (diff.stats.size() == 0) continue;
- addNetworkStats(atomTag, pulledData, diff);
+ switch (atomTag) {
+ case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED:
+ addBytesTransferByTagAndMeteredAtoms(diff, pulledData);
+ break;
+ default:
+ addNetworkStats(atomTag, pulledData, diff);
+ }
}
return StatsManager.PULL_SUCCESS;
}
@@ -879,7 +934,7 @@ public class StatsPullAtomService extends SystemService {
}
e.writeInt(entry.uid);
e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
- if (statsExt.withFgbg) {
+ if (statsExt.slicedByFgbg) {
e.writeInt(entry.set);
}
e.writeLong(entry.rxBytes);
@@ -890,14 +945,38 @@ public class StatsPullAtomService extends SystemService {
}
}
+ private void addBytesTransferByTagAndMeteredAtoms(@NonNull NetworkStatsExt statsExt,
+ @NonNull List<StatsEvent> pulledData) {
+ final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling
+ for (int i = 0; i < statsExt.stats.size(); i++) {
+ statsExt.stats.getValues(i, entry);
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED)
+ .addBooleanAnnotation(ANNOTATION_ID_TRUNCATE_TIMESTAMP, true)
+ .writeInt(entry.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
+ .writeBoolean(entry.metered == NetworkStats.METERED_YES)
+ .writeInt(entry.tag)
+ .writeLong(entry.rxBytes)
+ .writeLong(entry.rxPackets)
+ .writeLong(entry.txBytes)
+ .writeLong(entry.txPackets)
+ .build();
+ pulledData.add(e);
+ }
+ }
+
/**
* Create a snapshot of NetworkStats since boot, but add 1 bucket duration before boot as a
* buffer to ensure at least one full bucket will be included.
* Note that this should be only used to calculate diff since the snapshot might contains
* some traffic before boot.
*/
- @Nullable private NetworkStats getUidNetworkStatsSnapshot(
- @NonNull NetworkTemplate template, boolean withFgbg) {
+ @Nullable private NetworkStats getUidNetworkStatsSnapshot(int transport, boolean includeTags) {
+ final NetworkTemplate template = (transport == TRANSPORT_CELLULAR)
+ ? NetworkTemplate.buildTemplateMobileWithRatType(
+ /*subscriptionId=*/null, NETWORK_TYPE_ALL)
+ : NetworkTemplate.buildTemplateWifiWildcard();
final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
@@ -906,38 +985,72 @@ public class StatsPullAtomService extends SystemService {
try {
final NetworkStats stats = getNetworkStatsSession().getSummaryForAllUid(template,
currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
- currentTimeInMillis, /*includeTags=*/false);
- return withFgbg ? rollupNetworkStatsByFgbg(stats) : stats.groupedByUid();
+ currentTimeInMillis, includeTags);
+ return stats;
} catch (RemoteException | NullPointerException e) {
- Slog.e(TAG, "Pulling netstats for " + template
- + " fgbg= " + withFgbg + " bytes has error", e);
+ Slog.e(TAG, "Pulling netstats for template=" + template + " and includeTags="
+ + includeTags + " causes error", e);
}
return null;
}
+ @NonNull private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) {
+ return sliceNetworkStats(stats,
+ (newEntry, oldEntry) -> {
+ newEntry.uid = oldEntry.uid;
+ newEntry.set = oldEntry.set;
+ });
+ }
+
+ @NonNull private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) {
+ return sliceNetworkStats(stats,
+ (newEntry, oldEntry) -> {
+ newEntry.uid = oldEntry.uid;
+ newEntry.tag = oldEntry.tag;
+ newEntry.metered = oldEntry.metered;
+ });
+ }
+
/**
- * Allows rollups per UID but keeping the set (foreground/background) slicing.
- * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java
+ * Slices NetworkStats along the dimensions specified in the slicer lambda and aggregates over
+ * non-sliced dimensions.
+ *
+ * This function iterates through each NetworkStats.Entry, sets its dimensions equal to the
+ * default state (with the presumption that we don't want to slice on anything), and then
+ * applies the slicer lambda to allow users to control which dimensions to slice on. This is
+ * adapted from groupedByUid within NetworkStats.java
+ *
+ * @param slicer An operation taking into two parameters, new NetworkStats.Entry and old
+ * NetworkStats.Entry, that should be used to copy state from the old to the new.
+ * This is useful for slicing by particular dimensions. For example, if we wished
+ * to slice by uid and tag, we could write the following lambda:
+ * (new, old) -> {
+ * new.uid = old.uid;
+ * new.tag = old.tag;
+ * }
+ * If no slicer is provided, the data is not sliced by any dimensions.
+ * @return new NeworkStats object appropriately sliced
*/
- @NonNull private NetworkStats rollupNetworkStatsByFgbg(@NonNull NetworkStats stats) {
+ @NonNull private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
+ @Nullable BiConsumer<NetworkStats.Entry, NetworkStats.Entry> slicer) {
final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1);
final NetworkStats.Entry entry = new NetworkStats.Entry();
+ entry.uid = NetworkStats.UID_ALL;
entry.iface = NetworkStats.IFACE_ALL;
+ entry.set = NetworkStats.SET_ALL;
entry.tag = NetworkStats.TAG_NONE;
entry.metered = NetworkStats.METERED_ALL;
entry.roaming = NetworkStats.ROAMING_ALL;
+ entry.defaultNetwork = NetworkStats.DEFAULT_NETWORK_ALL;
- int size = stats.size();
- final NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values
- for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry recycle = new NetworkStats.Entry(); // used for retrieving values
+ for (int i = 0; i < stats.size(); i++) {
stats.getValues(i, recycle);
+ if (slicer != null) {
+ slicer.accept(entry, recycle);
+ }
- // Skip specific tags, since already counted in TAG_NONE
- if (recycle.tag != NetworkStats.TAG_NONE) continue;
-
- entry.set = recycle.set; // Allows slicing by background/foreground
- entry.uid = recycle.uid;
entry.rxBytes = recycle.rxBytes;
entry.rxPackets = recycle.rxPackets;
entry.txBytes = recycle.txBytes;
@@ -987,6 +1100,19 @@ public class StatsPullAtomService extends SystemService {
);
}
+ private void registerBytesTransferByTagAndMetered() {
+ int tagId = FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED;
+ PullAtomMetadata metadata = new PullAtomMetadata.Builder()
+ .setAdditiveFields(new int[] {4, 5, 6, 7})
+ .build();
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ metadata,
+ BackgroundThread.getExecutor(),
+ mStatsCallbackImpl
+ );
+ }
+
private void registerBluetoothBytesTransfer() {
int tagId = FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index e3b1152cd7b7..323ac7b8806e 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.tv;
+import static android.media.AudioManager.DEVICE_NONE;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
@@ -2047,6 +2048,36 @@ public final class TvInputManagerService extends SystemService {
return clientPid;
}
+ /**
+ * Add a hardware device in the TvInputHardwareManager for CTS testing
+ * purpose.
+ *
+ * @param device id of the adding hardware device.
+ */
+ @Override
+ public void addHardwareDevice(int deviceId) {
+ TvInputHardwareInfo info = new TvInputHardwareInfo.Builder()
+ .deviceId(deviceId)
+ .type(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI)
+ .audioType(DEVICE_NONE)
+ .audioAddress("0")
+ .hdmiPortId(0)
+ .build();
+ mTvInputHardwareManager.onDeviceAvailable(info, null);
+ return;
+ }
+
+ /**
+ * Remove a hardware device in the TvInputHardwareManager for CTS testing
+ * purpose.
+ *
+ * @param device id of the removing hardware device.
+ */
+ @Override
+ public void removeHardwareDevice(int deviceId) {
+ mTvInputHardwareManager.onDeviceUnavailable(deviceId);
+ }
+
private int getClientPidLocked(String sessionId)
throws IllegalStateException {
if (mSessionIdToSessionStateMap.get(sessionId) == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b5b82d39b921..5a6e0a1ff9c3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6535,14 +6535,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
final int requestedOrientation = getRequestedConfigurationOrientation();
- final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
+ final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED
+ && !mDisplayContent.ignoreRotationForApps();
final int orientation = orientationRequested
? requestedOrientation
: newParentConfiguration.orientation;
int rotation = newParentConfiguration.windowConfiguration.getRotation();
final boolean canChangeOrientation = handlesOrientationChangeFromDescendant();
- if (canChangeOrientation && mCompatDisplayInsets.mIsRotatable
- && !mCompatDisplayInsets.mIsFloating) {
+ if (canChangeOrientation && !mCompatDisplayInsets.mIsFloating) {
// Use parent rotation because the original display can rotate by requested orientation.
resolvedConfig.windowConfiguration.setRotation(rotation);
} else {
@@ -7628,7 +7628,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private final int mWidth;
private final int mHeight;
final boolean mIsFloating;
- final boolean mIsRotatable;
/**
* The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
@@ -7645,7 +7644,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** Constructs the environment to simulate the bounds behavior of the given container. */
CompatDisplayInsets(DisplayContent display, WindowContainer container) {
mIsFloating = container.getWindowConfiguration().tasksAreFloating();
- mIsRotatable = !mIsFloating && !display.ignoreRotationForApps();
if (mIsFloating) {
final Rect containerBounds = container.getWindowConfiguration().getBounds();
mWidth = containerBounds.width();
@@ -7702,7 +7700,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
- if (mIsRotatable && canChangeOrientation) {
+ if (canChangeOrientation) {
getBoundsByRotation(outBounds, rotation);
if (orientationRequested) {
getFrameByOrientation(outAppBounds, orientation);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 9b9b61340332..fc69ef555986 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2638,6 +2638,9 @@ class ActivityStack extends Task {
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */,
false /* deferResume */);
+ // Usually resuming a top activity triggers the next app transition, but nothing's got
+ // resumed in this case, so we need to execute it explicitly.
+ getDisplay().mDisplayContent.executeAppTransition();
} else {
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eb85db61754f..3272a5d90d4e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -99,6 +99,7 @@ import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
@@ -498,6 +499,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
private ActivityRecord mFixedRotationLaunchingApp;
+ private FixedRotationAnimationController mFixedRotationAnimationController;
+
final FixedRotationTransitionListener mFixedRotationTransitionListener =
new FixedRotationTransitionListener();
@@ -1106,12 +1109,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
void removeShellRoot(int windowType) {
- ShellRoot root = mShellRoots.get(windowType);
- if (root == null) {
- return;
+ synchronized(mWmService.mGlobalLock) {
+ ShellRoot root = mShellRoots.get(windowType);
+ if (root == null) {
+ return;
+ }
+ root.clear();
+ mShellRoots.remove(windowType);
}
- root.clear();
- mShellRoots.remove(windowType);
}
void setRemoteInsetsController(IDisplayWindowInsetsController controller) {
@@ -1485,6 +1490,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mFixedRotationLaunchingApp;
}
+ @VisibleForTesting
+ @Nullable FixedRotationAnimationController getFixedRotationAnimationController() {
+ return mFixedRotationAnimationController;
+ }
+
void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r) {
setFixedRotationLaunchingAppUnchecked(r, ROTATION_UNDEFINED);
}
@@ -1492,8 +1502,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) {
if (mFixedRotationLaunchingApp == null && r != null) {
mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation);
+ if (mFixedRotationAnimationController == null) {
+ mFixedRotationAnimationController = new FixedRotationAnimationController(this);
+ mFixedRotationAnimationController.hide();
+ }
} else if (mFixedRotationLaunchingApp != null && r == null) {
mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this);
+ finishFixedRotationAnimationIfPossible();
}
mFixedRotationLaunchingApp = r;
}
@@ -1582,6 +1597,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
+ /** Re-show the previously hidden windows if all seamless rotated windows are done. */
+ void finishFixedRotationAnimationIfPossible() {
+ final FixedRotationAnimationController controller = mFixedRotationAnimationController;
+ if (controller != null && !mDisplayRotation.hasSeamlessRotatingWindow()) {
+ controller.show();
+ mFixedRotationAnimationController = null;
+ }
+ }
+
/**
* Update rotation of the display.
*
@@ -3494,7 +3518,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) {
return;
}
-
+ ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target);
mInputMethodTarget = target;
mInputMethodTargetWaitingAnim = targetWaitingAnim;
assignWindowLayers(true /* setLayoutNeeded */);
@@ -3508,6 +3532,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
void setInputMethodInputTarget(WindowState target) {
if (mInputMethodInputTarget != target) {
+ ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
mInputMethodInputTarget = target;
updateImeControlTarget();
}
@@ -3515,6 +3540,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private void updateImeControlTarget() {
mInputMethodControlTarget = computeImeControlTarget();
+ ProtoLog.i(WM_DEBUG_IME, "updateImeControlTarget %s",
+ mInputMethodControlTarget.getWindow());
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 702df2a0fc63..96f236310d83 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -560,6 +560,7 @@ public class DisplayRotation {
}, true /* traverseTopToBottom */);
mSeamlessRotationCount = 0;
mRotatingSeamlessly = false;
+ mDisplayContent.finishFixedRotationAnimationIfPossible();
}
private void prepareSeamlessRotation() {
@@ -573,6 +574,10 @@ public class DisplayRotation {
return mRotatingSeamlessly;
}
+ boolean hasSeamlessRotatingWindow() {
+ return mSeamlessRotationCount > 0;
+ }
+
@VisibleForTesting
boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) {
// Display doesn't need to be frozen because application has been started in correct
@@ -646,6 +651,7 @@ public class DisplayRotation {
"Performing post-rotate rotation after seamless rotation");
// Finish seamless rotation.
mRotatingSeamlessly = false;
+ mDisplayContent.finishFixedRotationAnimationIfPossible();
updateRotationAndSendNewConfigIfChanged();
}
diff --git a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
new file mode 100644
index 000000000000..cc02e991c2ae
--- /dev/null
+++ b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
@@ -0,0 +1,166 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.AnimationSpecProto.WINDOW;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
+import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
+
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.proto.ProtoOutputStream;
+import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Transformation;
+
+import com.android.internal.R;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controller to fade out and in system ui when applying a fixed rotation transform to a window
+ * token.
+ *
+ * The system bars will be fade out when the fixed rotation transform starts and will be fade in
+ * once all surfaces have been rotated.
+ */
+public class FixedRotationAnimationController {
+
+ private final Context mContext;
+ private final WindowState mStatusBar;
+ private final WindowState mNavigationBar;
+ private final ArrayList<WindowToken> mAnimatedWindowToken = new ArrayList<>(2);
+ private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();
+
+ public FixedRotationAnimationController(DisplayContent displayContent) {
+ mContext = displayContent.mWmService.mContext;
+ final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
+ mStatusBar = displayPolicy.getStatusBar();
+ // Do not animate movable navigation bar (e.g. non-gesture mode).
+ mNavigationBar = !displayPolicy.navigationBarCanMove()
+ ? displayPolicy.getNavigationBar()
+ : null;
+ }
+
+ /** Applies show animation on the previously hidden window tokens. */
+ void show() {
+ for (int i = mAnimatedWindowToken.size() - 1; i >= 0; i--) {
+ final WindowToken windowToken = mAnimatedWindowToken.get(i);
+ fadeWindowToken(true /* show */, windowToken);
+ }
+ }
+
+ /** Applies hide animation on the window tokens which may be seamlessly rotated later. */
+ void hide() {
+ if (mNavigationBar != null) {
+ fadeWindowToken(false /* show */, mNavigationBar.mToken);
+ }
+ if (mStatusBar != null) {
+ fadeWindowToken(false /* show */, mStatusBar.mToken);
+ }
+ }
+
+ private void fadeWindowToken(boolean show, WindowToken windowToken) {
+ if (windowToken == null || windowToken.getParent() == null) {
+ return;
+ }
+
+ final Animation animation = AnimationUtils.loadAnimation(mContext,
+ show ? R.anim.fade_in : R.anim.fade_out);
+ final LocalAnimationAdapter.AnimationSpec windowAnimationSpec =
+ createAnimationSpec(animation);
+
+ final FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter(
+ windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken);
+
+ // We deferred the end of the animation when hiding the token, so we need to end it now that
+ // it's shown again.
+ final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
+ final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken);
+ if (runnable != null) {
+ runnable.run();
+ }
+ } : null;
+ windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
+ show /* hidden */, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback);
+ mAnimatedWindowToken.add(windowToken);
+ }
+
+ private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) {
+ return new LocalAnimationAdapter.AnimationSpec() {
+
+ final Transformation mTransformation = new Transformation();
+
+ @Override
+ public boolean getShowWallpaper() {
+ return true;
+ }
+
+ @Override
+ public long getDuration() {
+ return animation.getDuration();
+ }
+
+ @Override
+ public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
+ long currentPlayTime) {
+ mTransformation.clear();
+ animation.getTransformation(currentPlayTime, mTransformation);
+ t.setAlpha(leash, mTransformation.getAlpha());
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.println(animation);
+ }
+
+ @Override
+ public void dumpDebugInner(ProtoOutputStream proto) {
+ final long token = proto.start(WINDOW);
+ proto.write(ANIMATION, animation.toString());
+ proto.end(token);
+ }
+ };
+ }
+
+ private class FixedRotationAnimationAdapter extends LocalAnimationAdapter {
+ private final boolean mShow;
+ private final WindowToken mToken;
+
+ FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec,
+ SurfaceAnimationRunner surfaceAnimationRunner, boolean show,
+ WindowToken token) {
+ super(windowAnimationSpec, surfaceAnimationRunner);
+ mShow = show;
+ mToken = token;
+ }
+
+ @Override
+ public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ // We defer the end of the hide animation to ensure the tokens stay hidden until
+ // we show them again.
+ if (!mShow) {
+ mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback);
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 7491376cd152..a0985fc48422 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -65,9 +65,16 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
// Target should still be the same.
if (isImeTargetFromDisplayContentAndImeSame()) {
final InsetsControlTarget target = mDisplayContent.mInputMethodControlTarget;
- ProtoLog.d(WM_DEBUG_IME, "call showInsets(ime) on %s",
+
+ ProtoLog.i(WM_DEBUG_IME, "call showInsets(ime) on %s",
target.getWindow() != null ? target.getWindow().getName() : "");
target.showInsets(WindowInsets.Type.ime(), true /* fromIme */);
+ if (target != mImeTargetFromIme && mImeTargetFromIme != null) {
+ ProtoLog.w(WM_DEBUG_IME,
+ "showInsets(ime) was requested by different window: %s ",
+ (mImeTargetFromIme.getWindow() != null
+ ? mImeTargetFromIme.getWindow().getName() : ""));
+ }
}
abortShowImePostLayout();
};
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index a6a21fc55770..6a4975950f1a 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -24,6 +24,7 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.ViewRootImpl.sNewInsetsMode;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL;
import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED;
@@ -40,6 +41,7 @@ import android.view.SurfaceControl.Transaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.function.TriConsumer;
+import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
@@ -134,6 +136,7 @@ class InsetsSourceProvider {
// animate-out as new one animates-in.
mWin.cancelAnimation();
}
+ ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
mWin = win;
mFrameProvider = frameProvider;
mImeFrameProvider = imeFrameProvider;
@@ -299,6 +302,8 @@ class InsetsSourceProvider {
updateVisibility();
mControl = new InsetsSourceControl(mSource.getType(), leash,
new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
+ ProtoLog.d(WM_DEBUG_IME,
+ "InsetsSource Control %s for target %s", mControl, mControlTarget);
}
void startSeamlessRotation() {
@@ -349,6 +354,9 @@ class InsetsSourceProvider {
final boolean isClientControlled = mControlTarget != null
&& mControlTarget.isClientControlled();
mSource.setVisible(mServerVisible && (!isClientControlled || mClientVisible));
+ ProtoLog.d(WM_DEBUG_IME,
+ "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
+ mServerVisible, mClientVisible);
}
InsetsSourceControl getControl(InsetsControlTarget target) {
@@ -391,6 +399,44 @@ class InsetsSourceProvider {
return mImeOverrideFrame;
}
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "InsetsSourceProvider");
+ pw.print(prefix + " mSource="); mSource.dump(prefix + " ", pw);
+ if (mControl != null) {
+ pw.print(prefix + " mControl=");
+ mControl.dump(prefix + " ", pw);
+ }
+ pw.print(prefix + " mFakeControl="); mFakeControl.dump(prefix + " ", pw);
+ pw.print(" mIsLeashReadyForDispatching="); pw.print(mIsLeashReadyForDispatching);
+ pw.print(" mImeOverrideFrame="); pw.print(mImeOverrideFrame.toString());
+ if (mWin != null) {
+ pw.print(prefix + " mWin=");
+ mWin.dump(pw, prefix + " ", false /* dumpAll */);
+ }
+ if (mAdapter != null) {
+ pw.print(prefix + " mAdapter=");
+ mAdapter.dump(pw, prefix + " ");
+ }
+ if (mControlTarget != null) {
+ pw.print(prefix + " mControlTarget=");
+ if (mControlTarget.getWindow() != null) {
+ mControlTarget.getWindow().dump(pw, prefix + " ", false /* dumpAll */);
+ }
+ }
+ if (mPendingControlTarget != null) {
+ pw.print(prefix + " mPendingControlTarget=");
+ if (mPendingControlTarget.getWindow() != null) {
+ mPendingControlTarget.getWindow().dump(pw, prefix + " ", false /* dumpAll */);
+ }
+ }
+ if (mFakeControlTarget != null) {
+ pw.print(prefix + " mFakeControlTarget=");
+ if (mFakeControlTarget.getWindow() != null) {
+ mFakeControlTarget.getWindow().dump(pw, prefix + " ", false /* dumpAll */);
+ }
+ }
+ }
+
private class ControlAdapter implements AnimationAdapter {
private SurfaceControl mCapturedLeash;
@@ -410,6 +456,9 @@ class InsetsSourceProvider {
t.setAlpha(animationLeash, 1 /* alpha */);
t.hide(animationLeash);
}
+ ProtoLog.i(WM_DEBUG_IME,
+ "ControlAdapter startAnimation mSource: %s controlTarget: %s", mSource,
+ mControlTarget);
mCapturedLeash = animationLeash;
final Rect frame = mWin.getWindowFrames().mFrame;
@@ -424,6 +473,9 @@ class InsetsSourceProvider {
mControlTarget = null;
mAdapter = null;
setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
+ ProtoLog.i(WM_DEBUG_IME,
+ "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
+ mSource, mControlTarget);
}
}
@@ -439,6 +491,8 @@ class InsetsSourceProvider {
@Override
public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "ControlAdapter");
+ pw.print(prefix + " mCapturedLeash="); pw.print(mCapturedLeash);
}
@Override
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 9798d77c5975..77bc37f0c2d7 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -29,6 +29,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
@@ -42,6 +44,8 @@ import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowManager;
+import com.android.server.protolog.common.ProtoLog;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.function.Consumer;
@@ -289,7 +293,10 @@ class InsetsStateController {
// Make sure that we always have a control target for the IME, even if the IME target is
// null. Otherwise there is no leash that will hide it and IME becomes "randomly" visible.
- onControlChanged(ITYPE_IME, imeTarget != null ? imeTarget : mEmptyImeControlTarget);
+ InsetsControlTarget target = imeTarget != null ? imeTarget : mEmptyImeControlTarget;
+ onControlChanged(ITYPE_IME, target);
+ ProtoLog.d(WM_DEBUG_IME, "onImeControlTargetChanged %s",
+ target != null ? target.getWindow() : "null");
notifyPendingInsetsControlChanged();
}
@@ -440,5 +447,11 @@ class InsetsStateController {
pw.println(InsetsState.typeToString(mTypeControlTargetMap.keyAt(i)) + " -> "
+ mTypeControlTargetMap.valueAt(i));
}
+ pw.println(prefix + " " + "InsetsSourceProviders map:");
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ pw.print(prefix + " ");
+ pw.println(InsetsState.typeToString(mProviders.keyAt(i)) + " -> ");
+ mProviders.valueAt(i).dump(pw, prefix);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
index 99f710bd8bd4..7a38bb65f73b 100644
--- a/services/core/java/com/android/server/wm/ShellRoot.java
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -156,4 +156,3 @@ public class ShellRoot {
}
}
}
-
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 42342a60ba16..0143eb1abe03 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -489,6 +489,12 @@ class SurfaceAnimator {
static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
/**
+ * Animation when a fixed rotation transform is applied to a window token.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
+
+ /**
* Bitmask to include all animation types. This is NOT an {@link AnimationType}
* @hide
*/
@@ -505,7 +511,8 @@ class SurfaceAnimator {
ANIMATION_TYPE_DIMMER,
ANIMATION_TYPE_RECENTS,
ANIMATION_TYPE_WINDOW_ANIMATION,
- ANIMATION_TYPE_INSETS_CONTROL
+ ANIMATION_TYPE_INSETS_CONTROL,
+ ANIMATION_TYPE_FIXED_TRANSFORM
})
@Retention(RetentionPolicy.SOURCE)
@interface AnimationType {}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 159c59b86b43..eee4e7795252 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6191,6 +6191,7 @@ public class WindowManagerService extends IWindowManager.Stub
final int displayId = dc.getDisplayId();
final WindowState inputMethodTarget = dc.mInputMethodTarget;
final WindowState inputMethodInputTarget = dc.mInputMethodInputTarget;
+ final InsetsControlTarget inputMethodControlTarget = dc.mInputMethodControlTarget;
if (inputMethodTarget != null) {
pw.print(" mInputMethodTarget in display# "); pw.print(displayId);
pw.print(' '); pw.println(inputMethodTarget);
@@ -6199,6 +6200,10 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mInputMethodInputTarget in display# "); pw.print(displayId);
pw.print(' '); pw.println(inputMethodInputTarget);
}
+ if (inputMethodControlTarget != null) {
+ pw.print(" inputMethodControlTarget in display# "); pw.print(displayId);
+ pw.print(' '); pw.println(inputMethodControlTarget.getWindow());
+ }
});
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
pw.print(" mLastDisplayFreezeDuration=");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e9aff88d0f80..4f1893eb6c13 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -113,6 +113,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
@@ -334,6 +335,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean mDragResizing;
private boolean mDragResizingChangeReported = true;
private int mResizeMode;
+ private boolean mResizeForBlastSyncReported;
+
/**
* Special mode that is intended only for the rounded corner overlay: during rotation
* transition, we un-rotate the window token such that the window appears as it did before the
@@ -1370,11 +1373,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// variables, because mFrameSizeChanged only tracks the width and height changing.
updateLastFrames();
+ // Add a window that is using blastSync to the resizing list if it hasn't been reported
+ // already. This because the window is waiting on a finishDrawing from the client.
if (didFrameInsetsChange
|| winAnimator.mSurfaceResized
|| configChanged
|| dragResizingChanged
- || mReportOrientationChanged) {
+ || mReportOrientationChanged
+ || requestResizeForBlastSync()) {
ProtoLog.v(WM_DEBUG_RESIZE,
"Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b "
+ "dragResizingChanged=%b reportOrientationChanged=%b",
@@ -3483,6 +3489,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mReportOrientationChanged = false;
mDragResizingChangeReported = true;
mWinAnimator.mSurfaceResized = false;
+ mResizeForBlastSyncReported = true;
mWindowFrames.resetInsetsChanged();
final Rect frame = mWindowFrames.mCompatFrame;
@@ -3553,6 +3560,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* Called when the insets state changed.
*/
void notifyInsetsChanged() {
+ ProtoLog.d(WM_DEBUG_IME, "notifyInsetsChanged for %s ", this);
try {
mClient.insetsChanged(getInsetsState());
} catch (RemoteException e) {
@@ -3562,6 +3570,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
public void notifyInsetsControlChanged() {
+ ProtoLog.d(WM_DEBUG_IME, "notifyInsetsControlChanged for %s ", this);
final InsetsStateController stateController =
getDisplayContent().getInsetsStateController();
try {
@@ -5500,7 +5509,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
long getFrameNumber() {
- return mFrameNumber;
+ // Return the frame number in which changes requested in this layout will be rendered or
+ // -1 if we do not expect the frame to be rendered.
+ return getFrameLw().isEmpty() ? -1 : mFrameNumber;
}
void setFrameNumber(long frameNumber) {
@@ -5733,6 +5744,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (!willSync) {
return false;
}
+ mResizeForBlastSyncReported = false;
mLocalSyncId = mBLASTSyncEngine.startSyncSet(this);
addChildrenToSyncSet(mLocalSyncId);
@@ -5777,4 +5789,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWaitingListener = null;
return mWinAnimator.finishDrawingLocked(null);
}
+
+ private boolean requestResizeForBlastSync() {
+ return useBLASTSync() && !mResizeForBlastSyncReported;
+ }
}
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index d99299b5f07c..e790a196ad64 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -118,14 +118,18 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path,
}
binder::Status BinderIncrementalService::createStorage(
- const std::string& path, const content::pm::DataLoaderParamsParcel& params,
- const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener,
- int32_t createMode, int32_t* _aidl_return) {
+ const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params,
+ int32_t createMode,
+ const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener,
+ const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
+ const ::android::sp<::android::os::incremental::IStorageHealthListener>& healthListener,
+ int32_t* _aidl_return) {
*_aidl_return =
mImpl.createStorage(path, const_cast<content::pm::DataLoaderParamsParcel&&>(params),
- listener,
- android::incremental::IncrementalService::CreateOptions(
- createMode));
+ android::incremental::IncrementalService::CreateOptions(createMode),
+ statusListener,
+ const_cast<StorageHealthCheckParams&&>(healthCheckParams),
+ healthListener);
return ok();
}
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 659f6afcc03f..68549f5a8ff8 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -41,8 +41,11 @@ public:
binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final;
binder::Status createStorage(
const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params,
- const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener,
- int32_t createMode, int32_t* _aidl_return) final;
+ int32_t createMode,
+ const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener,
+ const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
+ const ::android::sp<IStorageHealthListener>& healthListener,
+ int32_t* _aidl_return) final;
binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId,
int32_t createMode, int32_t* _aidl_return) final;
binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath,
@@ -55,8 +58,7 @@ public:
binder::Status makeDirectories(int32_t storageId, const std::string& path,
int32_t* _aidl_return) final;
binder::Status makeFile(int32_t storageId, const std::string& path,
- const ::android::os::incremental::IncrementalNewFileParams& params,
- int32_t* _aidl_return) final;
+ const IncrementalNewFileParams& params, int32_t* _aidl_return) final;
binder::Status makeFileFromRange(int32_t storageId, const std::string& targetPath,
const std::string& sourcePath, int64_t start, int64_t end,
int32_t* _aidl_return) final;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index bf859b9b914d..66c7717d7987 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -410,9 +410,12 @@ auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator {
}
}
-StorageId IncrementalService::createStorage(
- std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams,
- const DataLoaderStatusListener& dataLoaderStatusListener, CreateOptions options) {
+StorageId IncrementalService::createStorage(std::string_view mountPoint,
+ content::pm::DataLoaderParamsParcel&& dataLoaderParams,
+ CreateOptions options,
+ const DataLoaderStatusListener& statusListener,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener& healthListener) {
LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
if (!path::isAbsolute(mountPoint)) {
LOG(ERROR) << "path is not absolute: " << mountPoint;
@@ -545,8 +548,8 @@ StorageId IncrementalService::createStorage(
// Done here as well, all data structures are in good state.
secondCleanupOnFailure.release();
- auto dataLoaderStub =
- prepareDataLoader(*ifs, std::move(dataLoaderParams), &dataLoaderStatusListener);
+ auto dataLoaderStub = prepareDataLoader(*ifs, std::move(dataLoaderParams), &statusListener,
+ std::move(healthCheckParams), &healthListener);
CHECK(dataLoaderStub);
mountIt->second = std::move(ifs);
@@ -1254,7 +1257,7 @@ bool IncrementalService::mountExistingImage(std::string_view root) {
dataLoaderParams.arguments = loader.arguments();
}
- prepareDataLoader(*ifs, std::move(dataLoaderParams), nullptr);
+ prepareDataLoader(*ifs, std::move(dataLoaderParams));
CHECK(ifs->dataLoaderStub);
std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints;
@@ -1338,14 +1341,18 @@ void IncrementalService::runCmdLooper() {
IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader(
IncFsMount& ifs, DataLoaderParamsParcel&& params,
- const DataLoaderStatusListener* externalListener) {
+ const DataLoaderStatusListener* statusListener,
+ StorageHealthCheckParams&& healthCheckParams, const StorageHealthListener* healthListener) {
std::unique_lock l(ifs.lock);
- prepareDataLoaderLocked(ifs, std::move(params), externalListener);
+ prepareDataLoaderLocked(ifs, std::move(params), statusListener, std::move(healthCheckParams),
+ healthListener);
return ifs.dataLoaderStub;
}
void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderParamsParcel&& params,
- const DataLoaderStatusListener* externalListener) {
+ const DataLoaderStatusListener* statusListener,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener* healthListener) {
if (ifs.dataLoaderStub) {
LOG(INFO) << "Skipped data loader preparation because it already exists";
return;
@@ -1360,7 +1367,8 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara
ifs.dataLoaderStub =
new DataLoaderStub(*this, ifs.mountId, std::move(params), std::move(fsControlParcel),
- externalListener, path::join(ifs.root, constants().mount));
+ statusListener, std::move(healthCheckParams), healthListener,
+ path::join(ifs.root, constants().mount));
}
template <class Duration>
@@ -1695,19 +1703,24 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) {
IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
DataLoaderParamsParcel&& params,
FileSystemControlParcel&& control,
- const DataLoaderStatusListener* externalListener,
+ const DataLoaderStatusListener* statusListener,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener* healthListener,
std::string&& healthPath)
: mService(service),
mId(id),
mParams(std::move(params)),
mControl(std::move(control)),
- mListener(externalListener ? *externalListener : DataLoaderStatusListener()),
+ mStatusListener(statusListener ? *statusListener : DataLoaderStatusListener()),
+ mHealthListener(healthListener ? *healthListener : StorageHealthListener()),
mHealthPath(std::move(healthPath)) {
+ // TODO(b/153874006): enable external health listener.
+ mHealthListener = {};
healthStatusOk();
}
IncrementalService::DataLoaderStub::~DataLoaderStub() {
- if (mId != kInvalidStorageId) {
+ if (isValid()) {
cleanupResources();
}
}
@@ -1725,13 +1738,14 @@ void IncrementalService::DataLoaderStub::cleanupResources() {
mStatusCondition.wait_until(lock, now + 60s, [this] {
return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
});
- mListener = {};
+ mStatusListener = {};
+ mHealthListener = {};
mId = kInvalidStorageId;
}
sp<content::pm::IDataLoader> IncrementalService::DataLoaderStub::getDataLoader() {
sp<IDataLoader> dataloader;
- auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader);
+ auto status = mService.mDataLoaderManager->getDataLoader(id(), &dataloader);
if (!status.isOk()) {
LOG(ERROR) << "Failed to get dataloader: " << status.toString8();
return {};
@@ -1767,15 +1781,15 @@ void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) {
auto oldStatus = mTargetStatus;
mTargetStatus = status;
mTargetStatusTs = Clock::now();
- LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
+ LOG(DEBUG) << "Target status update for DataLoader " << id() << ": " << oldStatus << " -> "
<< status << " (current " << mCurrentStatus << ")";
}
bool IncrementalService::DataLoaderStub::bind() {
bool result = false;
- auto status = mService.mDataLoaderManager->bindToDataLoader(mId, mParams, this, &result);
+ auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, this, &result);
if (!status.isOk() || !result) {
- LOG(ERROR) << "Failed to bind a data loader for mount " << mId;
+ LOG(ERROR) << "Failed to bind a data loader for mount " << id();
return false;
}
return true;
@@ -1786,9 +1800,9 @@ bool IncrementalService::DataLoaderStub::create() {
if (!dataloader) {
return false;
}
- auto status = dataloader->create(mId, mParams, mControl, this);
+ auto status = dataloader->create(id(), mParams, mControl, this);
if (!status.isOk()) {
- LOG(ERROR) << "Failed to start DataLoader: " << status.toString8();
+ LOG(ERROR) << "Failed to create DataLoader: " << status.toString8();
return false;
}
return true;
@@ -1799,7 +1813,7 @@ bool IncrementalService::DataLoaderStub::start() {
if (!dataloader) {
return false;
}
- auto status = dataloader->start(mId);
+ auto status = dataloader->start(id());
if (!status.isOk()) {
LOG(ERROR) << "Failed to start DataLoader: " << status.toString8();
return false;
@@ -1808,7 +1822,7 @@ bool IncrementalService::DataLoaderStub::start() {
}
bool IncrementalService::DataLoaderStub::destroy() {
- return mService.mDataLoaderManager->unbindFromDataLoader(mId).isOk();
+ return mService.mDataLoaderManager->unbindFromDataLoader(id()).isOk();
}
bool IncrementalService::DataLoaderStub::fsmStep() {
@@ -1867,8 +1881,8 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount
return binder::Status::
fromServiceSpecificError(-EINVAL, "onStatusChange came to invalid DataLoaderStub");
}
- if (mId != mountId) {
- LOG(ERROR) << "Mount ID mismatch: expected " << mId << ", but got: " << mountId;
+ if (id() != mountId) {
+ LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId;
return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
}
@@ -1884,7 +1898,7 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount
mCurrentStatus = newStatus;
targetStatus = mTargetStatus;
- listener = mListener;
+ listener = mStatusListener;
if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE) {
// For unavailable, unbind from DataLoader to ensure proper re-commit.
@@ -1892,7 +1906,7 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount
}
}
- LOG(DEBUG) << "Current status update for DataLoader " << mId << ": " << oldStatus << " -> "
+ LOG(DEBUG) << "Current status update for DataLoader " << id() << ": " << oldStatus << " -> "
<< newStatus << " (target " << targetStatus << ")";
if (listener) {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index c2a06ae83465..05f62b977a85 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -21,6 +21,8 @@
#include <android/content/pm/FileSystemControlParcel.h>
#include <android/content/pm/IDataLoaderStatusListener.h>
#include <android/os/incremental/BnIncrementalServiceConnector.h>
+#include <android/os/incremental/BnStorageHealthListener.h>
+#include <android/os/incremental/StorageHealthCheckParams.h>
#include <binder/IAppOpsCallback.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
@@ -56,10 +58,15 @@ using RawMetadata = incfs::RawMetadata;
using Clock = std::chrono::steady_clock;
using TimePoint = std::chrono::time_point<Clock>;
using Seconds = std::chrono::seconds;
+using BootClockTsUs = uint64_t;
using IDataLoaderStatusListener = ::android::content::pm::IDataLoaderStatusListener;
using DataLoaderStatusListener = ::android::sp<IDataLoaderStatusListener>;
+using StorageHealthCheckParams = ::android::os::incremental::StorageHealthCheckParams;
+using IStorageHealthListener = ::android::os::incremental::IStorageHealthListener;
+using StorageHealthListener = ::android::sp<IStorageHealthListener>;
+
class IncrementalService final {
public:
explicit IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir);
@@ -72,6 +79,8 @@ public:
static constexpr StorageId kInvalidStorageId = -1;
static constexpr StorageId kMaxStorageId = std::numeric_limits<int>::max();
+ static constexpr BootClockTsUs kMaxBootClockTsUs = std::numeric_limits<BootClockTsUs>::max();
+
enum CreateOptions {
TemporaryBind = 1,
PermanentBind = 2,
@@ -97,8 +106,9 @@ public:
StorageId createStorage(std::string_view mountPoint,
content::pm::DataLoaderParamsParcel&& dataLoaderParams,
- const DataLoaderStatusListener& dataLoaderStatusListener,
- CreateOptions options = CreateOptions::Default);
+ CreateOptions options, const DataLoaderStatusListener& statusListener,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener& healthListener);
StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
CreateOptions options = CreateOptions::Default);
StorageId openStorage(std::string_view path);
@@ -162,7 +172,9 @@ private:
DataLoaderStub(IncrementalService& service, MountId id,
content::pm::DataLoaderParamsParcel&& params,
content::pm::FileSystemControlParcel&& control,
- const DataLoaderStatusListener* externalListener, std::string&& healthPath);
+ const DataLoaderStatusListener* statusListener,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener* healthListener, std::string&& healthPath);
~DataLoaderStub();
// Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will
// result in an error.
@@ -213,7 +225,8 @@ private:
MountId mId = kInvalidStorageId;
content::pm::DataLoaderParamsParcel mParams;
content::pm::FileSystemControlParcel mControl;
- DataLoaderStatusListener mListener;
+ DataLoaderStatusListener mStatusListener;
+ StorageHealthListener mHealthListener;
std::condition_variable mStatusCondition;
int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
@@ -292,9 +305,13 @@ private:
DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs,
content::pm::DataLoaderParamsParcel&& params,
- const DataLoaderStatusListener* externalListener = nullptr);
+ const DataLoaderStatusListener* statusListener = nullptr,
+ StorageHealthCheckParams&& healthCheckParams = {},
+ const StorageHealthListener* healthListener = nullptr);
void prepareDataLoaderLocked(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params,
- const DataLoaderStatusListener* externalListener = nullptr);
+ const DataLoaderStatusListener* statusListener = nullptr,
+ StorageHealthCheckParams&& healthCheckParams = {},
+ const StorageHealthListener* healthListener = nullptr);
BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
StorageId findStorageId(std::string_view path) const;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 08fb486c8058..a76aa625ebc6 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -175,6 +175,10 @@ public:
ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
}
+ WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
+ std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final {
+ return incfs::waitForPendingReads(control, timeout, pendingReadsBuffer);
+ }
};
RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index abbf2f4c4424..a935ab99267e 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -69,6 +69,7 @@ public:
using Control = incfs::Control;
using FileId = incfs::FileId;
using ErrorCode = incfs::ErrorCode;
+ using WaitResult = incfs::WaitResult;
using ExistingMountCallback =
std::function<void(std::string_view root, std::string_view backingDir,
@@ -90,6 +91,9 @@ public:
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
virtual base::unique_fd openForSpecialOps(const Control& control, FileId id) const = 0;
virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0;
+ virtual WaitResult waitForPendingReads(
+ const Control& control, std::chrono::milliseconds timeout,
+ std::vector<incfs::ReadInfo>* pendingReadsBuffer) const = 0;
};
class AppOpsManagerWrapper {
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 2e4625cf85a1..2948b6a0f293 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -284,6 +284,9 @@ public:
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
+ MOCK_CONST_METHOD3(waitForPendingReads,
+ WaitResult(const Control& control, std::chrono::milliseconds timeout,
+ std::vector<incfs::ReadInfo>* pendingReadsBuffer));
MockIncFs() { ON_CALL(*this, listExistingMounts(_)).WillByDefault(Return()); }
@@ -292,12 +295,23 @@ public:
void openMountSuccess() {
ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth));
}
+ void waitForPendingReadsSuccess() {
+ ON_CALL(*this, waitForPendingReads(_, _, _))
+ .WillByDefault(Invoke(this, &MockIncFs::waitForPendingReadsForHealth));
+ }
static constexpr auto kPendingReadsFd = 42;
Control openMountForHealth(std::string_view) {
return UniqueControl(IncFs_CreateControl(-1, kPendingReadsFd, -1));
}
+ WaitResult waitForPendingReadsForHealth(
+ const Control& control, std::chrono::milliseconds timeout,
+ std::vector<incfs::ReadInfo>* pendingReadsBuffer) const {
+ pendingReadsBuffer->push_back({.bootClockTsUs = 0});
+ return android::incfs::WaitResult::HaveData;
+ }
+
RawMetadata getMountInfoMetadata(const Control& control, std::string_view path) {
metadata::Mount m;
m.mutable_storage()->set_id(100);
@@ -499,9 +513,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) {
mVold->mountIncFsFails();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(0);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_LT(storageId, 0);
}
@@ -510,9 +524,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel)
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(0);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_LT(storageId, 0);
}
@@ -523,9 +537,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) {
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_LT(storageId, 0);
}
@@ -537,9 +551,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) {
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_LT(storageId, 0);
}
@@ -555,9 +569,9 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_LT(storageId, 0);
}
@@ -574,9 +588,9 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
mIncrementalService->deleteStorage(storageId);
}
@@ -594,9 +608,9 @@ TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
// Simulated crash/other connection breakage.
mDataLoaderManager->setDataLoaderStatusDestroyed();
@@ -616,9 +630,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
mDataLoaderManager->setDataLoaderStatusCreated();
ASSERT_TRUE(mIncrementalService->startLoading(storageId));
@@ -639,9 +653,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
ASSERT_TRUE(mIncrementalService->startLoading(storageId));
mDataLoaderManager->setDataLoaderStatusCreated();
@@ -661,9 +675,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
mDataLoaderManager->setDataLoaderStatusUnavailable();
}
@@ -672,6 +686,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mIncFs->openMountSuccess();
+ mIncFs->waitForPendingReadsSuccess();
mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
mDataLoaderManager->bindToDataLoaderSuccess();
@@ -685,9 +700,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1);
EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
mDataLoaderManager->setDataLoaderStatusUnavailable();
ASSERT_NE(nullptr, mLooper->mCallback);
@@ -712,9 +727,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
// Not expecting callback removal.
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
}
@@ -739,9 +754,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChang
// After callback is called, disable read logs and remove callback.
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(1);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
ASSERT_NE(nullptr, mAppOpsManager->mStoredCallback.get());
@@ -762,9 +777,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
ASSERT_LT(mDataLoader->setStorageParams(true), 0);
}
@@ -785,9 +800,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
ASSERT_GE(storageId, 0);
ASSERT_LT(mDataLoader->setStorageParams(true), 0);
}
@@ -799,9 +814,9 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) {
mDataLoaderManager->bindToDataLoaderSuccess();
mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
std::string dir_path("test");
// Expecting incfs to call makeDir on a path like:
@@ -823,9 +838,9 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) {
mDataLoaderManager->bindToDataLoaderSuccess();
mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
- IncrementalService::CreateOptions::CreateNew);
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
auto first = "first"sv;
auto second = "second"sv;
auto third = "third"sv;
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index dc3fa2a048f6..17378285276f 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -142,9 +142,12 @@ public class ConversationInfo {
return hasShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED);
}
- /** Whether the shortcut for this conversation is cached in Shortcut Service. */
- public boolean isShortcutCached() {
- return hasShortcutFlags(ShortcutInfo.FLAG_CACHED);
+ /**
+ * Whether the shortcut for this conversation is cached in Shortcut Service, with cache owner
+ * set as notifications.
+ */
+ public boolean isShortcutCachedForNotification() {
+ return hasShortcutFlags(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
}
/** Whether this conversation is marked as important by the user. */
@@ -223,7 +226,7 @@ public class ConversationInfo {
if (isShortcutLongLived()) {
sb.append("Liv");
}
- if (isShortcutCached()) {
+ if (isShortcutCachedForNotification()) {
sb.append("Cac");
}
sb.append("]");
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 bbb0215788fb..63b716206313 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -294,14 +294,14 @@ public class DataManager {
if (notificationListener != null) {
String packageName = packageData.getPackageName();
packageData.forAllConversations(conversationInfo -> {
- if (conversationInfo.isShortcutCached()
+ if (conversationInfo.isShortcutCachedForNotification()
&& conversationInfo.getNotificationChannelId() == null
&& !notificationListener.hasActiveNotifications(
packageName, conversationInfo.getShortcutId())) {
mShortcutServiceInternal.uncacheShortcuts(userId,
mContext.getPackageName(), packageName,
Collections.singletonList(conversationInfo.getShortcutId()),
- userId);
+ userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
}
});
}
@@ -821,12 +821,12 @@ public class DataManager {
// The shortcut was cached by Notification Manager synchronously when the
// associated notification was posted. Uncache it here when all the
// associated notifications are removed.
- if (conversationInfo.isShortcutCached()
+ if (conversationInfo.isShortcutCachedForNotification()
&& conversationInfo.getNotificationChannelId() == null) {
mShortcutServiceInternal.uncacheShortcuts(mUserId,
mContext.getPackageName(), sbn.getPackageName(),
Collections.singletonList(conversationInfo.getShortcutId()),
- mUserId);
+ mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
}
} else {
mActiveNotifCounts.put(conversationKey, count);
@@ -891,12 +891,12 @@ public class DataManager {
ConversationInfo conversationInfo =
packageData != null ? packageData.getConversationInfo(shortcutId) : null;
if (conversationInfo != null
- && conversationInfo.isShortcutCached()
+ && conversationInfo.isShortcutCachedForNotification()
&& conversationInfo.getNotificationChannelId() == null) {
mShortcutServiceInternal.uncacheShortcuts(mUserId,
mContext.getPackageName(), packageName,
Collections.singletonList(shortcutId),
- mUserId);
+ mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
}
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
index d338b587e059..ade01dc6afa6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -19,7 +19,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealM
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS;
+import static com.android.server.blob.BlobStoreConfig.DeviceConfigProperties.SESSION_EXPIRY_TIMEOUT_MS;
import static com.google.common.truth.Truth.assertThat;
@@ -93,6 +93,7 @@ public class BlobStoreManagerServiceTest {
doReturn(true).when(mBlobsDir).exists();
doReturn(new File[0]).when(mBlobsDir).listFiles();
doReturn(true).when(() -> BlobStoreConfig.hasLeaseWaitTimeElapsed(anyLong()));
+ doCallRealMethod().when(() -> BlobStoreConfig.hasSessionExpired(anyLong()));
mContext = InstrumentationRegistry.getTargetContext();
mHandler = new TestHandler(Looper.getMainLooper());
@@ -236,7 +237,7 @@ public class BlobStoreManagerServiceTest {
public void testHandleIdleMaintenance_deleteStaleSessions() throws Exception {
// Setup sessions
final File sessionFile1 = mock(File.class);
- doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS + 1000)
+ doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MS + 1000)
.when(sessionFile1).lastModified();
final long sessionId1 = 342;
final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
@@ -256,7 +257,7 @@ public class BlobStoreManagerServiceTest {
mUserSessions.append(sessionId2, session2);
final File sessionFile3 = mock(File.class);
- doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS - 2000)
+ doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MS - 2000)
.when(sessionFile3).lastModified();
final long sessionId3 = 9484;
final BlobHandle blobHandle3 = BlobHandle.createWithSha256("digest3".getBytes(),
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index 425c7247e50f..d45589d90ce3 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -288,7 +288,8 @@ public class OverrideValidatorImplTest {
public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptin_allowOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
- .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1).build();
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
@@ -296,19 +297,23 @@ public class OverrideValidatorImplTest {
.withTargetSdk(TARGET_SDK)
.withPackageName(PACKAGE_NAME).build());
- OverrideAllowedState allowedState =
+ OverrideAllowedState stateTargetSdkGreaterChange =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
- assertThat(allowedState)
+ assertThat(stateTargetSdkGreaterChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
}
@Test
public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptout_rejectOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
- .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
- .addTargetSdkChangeWithId(TARGET_SDK, 2).build();
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
@@ -319,14 +324,10 @@ public class OverrideValidatorImplTest {
OverrideAllowedState stateTargetSdkLessChange =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
- OverrideAllowedState stateTargetSdkEqualChange =
- overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange).isEqualTo(
new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK,
TARGET_SDK_BEFORE));
- assertThat(stateTargetSdkEqualChange).isEqualTo(
- new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, TARGET_SDK));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 724048b1b8ee..4a774898e1b5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1997,19 +1997,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
Sets.newSet(
- UserManager.DISALLOW_CONFIG_DATE_TIME,
- UserManager.DISALLOW_BLUETOOTH_SHARING,
- UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
- UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
- UserManager.DISALLOW_CONFIG_PRIVATE_DNS,
- UserManager.DISALLOW_CONFIG_TETHERING,
- UserManager.DISALLOW_DATA_ROAMING,
- UserManager.DISALLOW_SAFE_BOOT,
- UserManager.DISALLOW_SMS,
- UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_AIRPLANE_MODE,
- UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
- UserManager.DISALLOW_UNMUTE_MICROPHONE
+ UserManager.DISALLOW_CONFIG_DATE_TIME,
+ UserManager.DISALLOW_CONFIG_PRIVATE_DNS
);
private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS =
@@ -2021,7 +2011,17 @@ public class DevicePolicyManagerTest extends DpmTestBase {
UserManager.DISALLOW_CONTENT_SUGGESTIONS,
UserManager.DISALLOW_DEBUGGING_FEATURES,
UserManager.DISALLOW_SHARE_LOCATION,
- UserManager.DISALLOW_OUTGOING_CALLS
+ UserManager.DISALLOW_OUTGOING_CALLS,
+ UserManager.DISALLOW_BLUETOOTH_SHARING,
+ UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
+ UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
+ UserManager.DISALLOW_CONFIG_TETHERING,
+ UserManager.DISALLOW_DATA_ROAMING,
+ UserManager.DISALLOW_SAFE_BOOT,
+ UserManager.DISALLOW_SMS,
+ UserManager.DISALLOW_USB_FILE_TRANSFER,
+ UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
+ UserManager.DISALLOW_UNMUTE_MICROPHONE
);
public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception {
@@ -2045,8 +2045,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
parentDpm.setCameraDisabled(admin1, true);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
- MockUtils.checkUserRestrictions(CALLER_USER_HANDLE),
+ MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM,
+ UserManager.DISALLOW_CAMERA),
eq(false));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(UserManager.DISALLOW_CAMERA),
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index f35eecf05f32..b7692f912e39 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -44,9 +44,9 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testUpdateOverlaysForUser() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
- installTargetPackage("some.other.target", USER);
- installOverlayPackage(OVERLAY, TARGET, USER);
+ addSystemPackage(target(TARGET), USER);
+ addSystemPackage(target("some.other.target"), USER);;
+ addSystemPackage(overlay(OVERLAY, TARGET), USER);
// do nothing, expect no change
final List<String> a = impl.updateOverlaysForUser(USER);
@@ -54,8 +54,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
assertTrue(a.contains(TARGET));
// upgrade overlay, keep target
- beginUpgradeOverlayPackage(OVERLAY, USER);
- endUpgradeOverlayPackage(OVERLAY, TARGET, USER);
+ addSystemPackage(overlay(OVERLAY, TARGET), USER);
final List<String> b = impl.updateOverlaysForUser(USER);
assertEquals(1, b.size());
@@ -67,7 +66,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
assertTrue(c.contains(TARGET));
// upgrade overlay, switch to new target
- addOverlayPackage(OVERLAY, "some.other.target", USER, true, false, 0);
+ addSystemPackage(overlay(OVERLAY, "some.other.target"), USER);
final List<String> d = impl.updateOverlaysForUser(USER);
assertEquals(2, d.size());
assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
@@ -81,23 +80,24 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testImmutableEnabledChange() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
- addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertFalse(o1.isEnabled());
assertFalse(o1.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o2);
assertTrue(o2.isEnabled());
assertFalse(o2.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
@@ -108,23 +108,24 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testMutableEnabledChangeHasNoEffect() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
- addOverlayPackage(OVERLAY, TARGET, USER, true, false, 0);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertFalse(o1.isEnabled());
assertTrue(o1.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, true, true, 0);
+ configureSystemOverlay(OVERLAY, true /* mutable */, true /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o2);
assertFalse(o2.isEnabled());
assertTrue(o2.isMutable);
- addOverlayPackage(OVERLAY, TARGET, USER, true, false, 0);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
@@ -135,15 +136,16 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testMutableEnabledToImmutableEnabled() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
final BiConsumer<Boolean, Boolean> setOverlay = (mutable, enabled) -> {
- addOverlayPackage(OVERLAY, TARGET, USER, mutable, enabled, 0);
+ configureSystemOverlay(OVERLAY, mutable, enabled, 0 /* priority */);
impl.updateOverlaysForUser(USER);
- final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
- assertNotNull(o1);
- assertEquals(enabled, o1.isEnabled());
- assertEquals(mutable, o1.isMutable);
+ final OverlayInfo o = impl.getOverlayInfo(OVERLAY, USER);
+ assertNotNull(o);
+ assertEquals(enabled, o.isEnabled());
+ assertEquals(mutable, o.isMutable);
};
// Immutable/enabled -> mutable/enabled
@@ -178,70 +180,76 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test
public void testMutablePriorityChange() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
- addOverlayPackage(OVERLAY, TARGET, USER, true, true, 0);
- addOverlayPackage(OVERLAY2, TARGET, USER, true, true, 1);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
+ configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 1 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertEquals(0, o1.priority);
+ assertFalse(o1.isEnabled());
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o2);
assertEquals(1, o2.priority);
+ assertFalse(o2.isEnabled());
// Overlay priority changing between reboots should not affect enable state of mutable
- // overlays
+ // overlays.
impl.setEnabled(OVERLAY, true, USER);
// Reorder the overlays
- addOverlayPackage(OVERLAY, TARGET, USER, true, true, 1);
- addOverlayPackage(OVERLAY2, TARGET, USER, true, true, 0);
+ configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 1 /* priority */);
+ configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
assertEquals(1, o3.priority);
+ assertTrue(o3.isEnabled());
final OverlayInfo o4 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o4);
assertEquals(0, o4.priority);
- assertTrue(o1.isEnabled());
+ assertFalse(o4.isEnabled());
}
@Test
public void testImmutablePriorityChange() {
final OverlayManagerServiceImpl impl = getImpl();
- installTargetPackage(TARGET, USER);
- addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0);
- addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 1);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */);
+ configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 1 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o1);
assertEquals(0, o1.priority);
+ assertTrue(o1.isEnabled());
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o2);
assertEquals(1, o2.priority);
-
- // Overlay priority changing between reboots should not affect enable state of mutable
- // overlays
- impl.setEnabled(OVERLAY, true, USER);
+ assertTrue(o2.isEnabled());
// Reorder the overlays
- addOverlayPackage(OVERLAY, TARGET, USER, false, true, 1);
- addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 0);
+ configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 1 /* priority */);
+ configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 0 /* priority */);
impl.updateOverlaysForUser(USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER);
assertNotNull(o3);
assertEquals(1, o3.priority);
+ assertTrue(o3.isEnabled());
final OverlayInfo o4 = impl.getOverlayInfo(OVERLAY2, USER);
assertNotNull(o4);
assertEquals(0, o4.priority);
- assertTrue(o1.isEnabled());
+ assertTrue(o4.isEnabled());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index cd7343235750..b25af0543829 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.content.om.OverlayInfo;
+import android.os.OverlayablePolicy;
import androidx.test.runner.AndroidJUnit4;
@@ -49,11 +50,9 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
private static final String OVERLAY3 = OVERLAY + "3";
private static final int USER3 = USER2 + 1;
- // tests: basics
-
@Test
- public void testGetOverlayInfo() throws Exception {
- installOverlayPackage(OVERLAY, TARGET, USER);
+ public void testGetOverlayInfo() {
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
final OverlayManagerServiceImpl impl = getImpl();
final OverlayInfo oi = impl.getOverlayInfo(OVERLAY, USER);
@@ -64,10 +63,10 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testGetOverlayInfosForTarget() throws Exception {
- installOverlayPackage(OVERLAY, TARGET, USER);
- installOverlayPackage(OVERLAY2, TARGET, USER);
- installOverlayPackage(OVERLAY3, TARGET, USER2);
+ public void testGetOverlayInfosForTarget() {
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ installNewPackage(overlay(OVERLAY3, TARGET), USER2);
final OverlayManagerServiceImpl impl = getImpl();
final List<OverlayInfo> ois = impl.getOverlayInfosForTarget(TARGET, USER);
@@ -89,11 +88,11 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testGetOverlayInfosForUser() throws Exception {
- installTargetPackage(TARGET, USER);
- installOverlayPackage(OVERLAY, TARGET, USER);
- installOverlayPackage(OVERLAY2, TARGET, USER);
- installOverlayPackage(OVERLAY3, TARGET2, USER);
+ public void testGetOverlayInfosForUser() {
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ installNewPackage(overlay(OVERLAY3, TARGET2), USER);
final OverlayManagerServiceImpl impl = getImpl();
final Map<String, List<OverlayInfo>> everything = impl.getOverlaysForUser(USER);
@@ -116,91 +115,86 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testPriority() throws Exception {
- installOverlayPackage(OVERLAY, TARGET, USER);
- installOverlayPackage(OVERLAY2, TARGET, USER);
- installOverlayPackage(OVERLAY3, TARGET, USER);
+ public void testPriority() {
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ installNewPackage(overlay(OVERLAY2, TARGET), USER);
+ installNewPackage(overlay(OVERLAY3, TARGET), USER);
final OverlayManagerServiceImpl impl = getImpl();
final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER);
final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER);
final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY3, USER);
- assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+ assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
assertTrue(impl.setLowestPriority(OVERLAY3, USER));
- assertOverlayInfoList(TARGET, USER, o3, o1, o2);
+ assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2);
assertTrue(impl.setHighestPriority(OVERLAY3, USER));
- assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+ assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER));
- assertOverlayInfoList(TARGET, USER, o2, o1, o3);
+ assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3);
}
@Test
- public void testOverlayInfoStateTransitions() throws Exception {
+ public void testOverlayInfoStateTransitions() {
final OverlayManagerServiceImpl impl = getImpl();
assertNull(impl.getOverlayInfo(OVERLAY, USER));
- installOverlayPackage(OVERLAY, TARGET, USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
- installTargetPackage(TARGET, USER);
+ final DummyDeviceState.PackageBuilder target = target(TARGET);
+ installNewPackage(target, USER);
assertState(STATE_DISABLED, OVERLAY, USER);
impl.setEnabled(OVERLAY, true, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
// target upgrades do not change the state of the overlay
- beginUpgradeTargetPackage(TARGET, USER);
- assertState(STATE_ENABLED, OVERLAY, USER);
-
- endUpgradeTargetPackage(TARGET, USER);
+ upgradePackage(target, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
- uninstallTargetPackage(TARGET, USER);
+ uninstallPackage(TARGET, USER);
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
- installTargetPackage(TARGET, USER);
+ installNewPackage(target, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
}
@Test
- public void testOnOverlayPackageUpgraded() throws Exception {
- final OverlayManagerServiceImpl impl = getImpl();
+ public void testOnOverlayPackageUpgraded() {
final DummyListener listener = getListener();
- installTargetPackage(TARGET, USER);
- installOverlayPackage(OVERLAY, TARGET, USER);
- impl.onOverlayPackageReplacing(OVERLAY, USER);
+ final DummyDeviceState.PackageBuilder target = target(TARGET);
+ final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
+ installNewPackage(target, USER);
+ installNewPackage(overlay, USER);
listener.count = 0;
- impl.onOverlayPackageReplaced(OVERLAY, USER);
- assertEquals(1, listener.count);
+ upgradePackage(overlay, USER);
+ assertEquals(2, listener.count);
// upgrade to a version where the overlay has changed its target
- beginUpgradeOverlayPackage(OVERLAY, USER);
- listener.count = 0;
- endUpgradeOverlayPackage(OVERLAY, "some.other.target", USER);
// expect once for the old target package, once for the new target package
- assertEquals(2, listener.count);
+ listener.count = 0;
+ final DummyDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
+ upgradePackage(overlay2, USER);
+ assertEquals(3, listener.count);
- beginUpgradeOverlayPackage(OVERLAY, USER);
listener.count = 0;
- endUpgradeOverlayPackage(OVERLAY, "some.other.target", USER);
- assertEquals(1, listener.count);
+ upgradePackage(overlay2, USER);
+ assertEquals(2, listener.count);
}
- // tests: listener interface
-
@Test
- public void testListener() throws Exception {
+ public void testListener() {
final OverlayManagerServiceImpl impl = getImpl();
final DummyListener listener = getListener();
- installOverlayPackage(OVERLAY, TARGET, USER);
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
assertEquals(1, listener.count);
listener.count = 0;
- installTargetPackage(TARGET, USER);
+ installNewPackage(target(TARGET), USER);
assertEquals(1, listener.count);
listener.count = 0;
@@ -211,4 +205,49 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
impl.setEnabled(OVERLAY, true, USER);
assertEquals(0, listener.count);
}
+
+ @Test
+ public void testConfigurator() {
+ final DummyPackageManagerHelper packageManager = getPackageManager();
+ packageManager.overlayableConfigurator = "actor";
+ packageManager.overlayableConfiguratorTargets = new String[]{TARGET};
+ reinitializeImpl();
+
+ installNewPackage(target("actor").setCertificate("one"), USER);
+ installNewPackage(target(TARGET)
+ .addOverlayable("TestResources")
+ .setCertificate("two"), USER);
+
+ final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
+ .setCertificate("one");
+ installNewPackage(overlay, USER);
+
+ final DummyIdmapDaemon idmapDaemon = getIdmapDaemon();
+ final DummyIdmapDaemon.IdmapHeader idmap = idmapDaemon.getIdmap(overlay.build().apkPath);
+ assertNotNull(idmap);
+ assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
+ idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
+ }
+
+ @Test
+ public void testConfiguratorDifferentSignatures() {
+ final DummyPackageManagerHelper packageManager = getPackageManager();
+ packageManager.overlayableConfigurator = "actor";
+ packageManager.overlayableConfiguratorTargets = new String[]{TARGET};
+ reinitializeImpl();
+
+ installNewPackage(target("actor").setCertificate("one"), USER);
+ installNewPackage(target(TARGET)
+ .addOverlayable("TestResources")
+ .setCertificate("two"), USER);
+
+ final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
+ .setCertificate("two");
+ installNewPackage(overlay, USER);
+
+ final DummyIdmapDaemon idmapDaemon = getIdmapDaemon();
+ final DummyIdmapDaemon.IdmapHeader idmap = idmapDaemon.getIdmap(overlay.build().apkPath);
+ assertNotNull(idmap);
+ assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 9eda718ed922..ec6a48182a25 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -17,6 +17,7 @@
package com.android.server.om;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -26,17 +27,19 @@ import android.content.om.OverlayInfo.State;
import android.content.om.OverlayableInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.util.ArrayMap;
import android.util.ArraySet;
import androidx.annotation.Nullable;
import com.android.internal.content.om.OverlayConfig;
+import org.junit.Assert;
import org.junit.Before;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Iterator;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -47,29 +50,48 @@ class OverlayManagerServiceImplTestsBase {
private OverlayManagerServiceImpl mImpl;
private DummyDeviceState mState;
private DummyListener mListener;
+ private DummyPackageManagerHelper mPackageManager;
+ private DummyIdmapDaemon mIdmapDaemon;
+ private OverlayConfig mOverlayConfig;
@Before
public void setUp() {
mState = new DummyDeviceState();
mListener = new DummyListener();
- final DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState);
+ mPackageManager = new DummyPackageManagerHelper(mState);
+ mIdmapDaemon = new DummyIdmapDaemon(mState);
+ mOverlayConfig = mock(OverlayConfig.class);
+ when(mOverlayConfig.getPriority(any())).thenReturn(OverlayConfig.DEFAULT_PRIORITY);
+ when(mOverlayConfig.isEnabled(any())).thenReturn(false);
+ when(mOverlayConfig.isMutable(any())).thenReturn(true);
+ reinitializeImpl();
+ }
- mImpl = new OverlayManagerServiceImpl(pmh,
- new DummyIdmapManager(mState, pmh),
+ void reinitializeImpl() {
+ mImpl = new OverlayManagerServiceImpl(mPackageManager,
+ new IdmapManager(mIdmapDaemon, mPackageManager),
new OverlayManagerSettings(),
- mState.mOverlayConfig,
+ mOverlayConfig,
new String[0],
mListener);
}
- public OverlayManagerServiceImpl getImpl() {
+ OverlayManagerServiceImpl getImpl() {
return mImpl;
}
- public DummyListener getListener() {
+ DummyListener getListener() {
return mListener;
}
+ DummyPackageManagerHelper getPackageManager() {
+ return mPackageManager;
+ }
+
+ DummyIdmapDaemon getIdmapDaemon() {
+ return mIdmapDaemon;
+ }
+
void assertState(@State int expected, final String overlayPackageName, int userId) {
final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
if (info == null) {
@@ -81,7 +103,7 @@ class OverlayManagerServiceImplTestsBase {
assertEquals(msg, expected, info.state);
}
- void assertOverlayInfoList(final String targetPackageName, int userId,
+ void assertOverlayInfoForTarget(final String targetPackageName, int userId,
OverlayInfo... overlayInfos) {
final List<OverlayInfo> expected =
mImpl.getOverlayInfosForTarget(targetPackageName, userId);
@@ -89,198 +111,202 @@ class OverlayManagerServiceImplTestsBase {
assertEquals(expected, actual);
}
- /**
- * Creates an overlay configured through {@link OverlayConfig}.
- *
- * @throws IllegalStateException if the package is already installed
- */
- void addOverlayPackage(String packageName, String targetPackageName, int userId,
- boolean mutable, boolean enabled, int priority) {
- mState.addOverlay(packageName, targetPackageName, userId, mutable, enabled, priority);
+ DummyDeviceState.PackageBuilder target(String packageName) {
+ return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
+ null /* targetOverlayableName */);
}
- /**
- * Adds the target package to the device.
- *
- * This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast.
- *
- * @throws IllegalStateException if the package is not currently installed
- */
- void installTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) != null) {
- throw new IllegalStateException("package already installed");
- }
- mState.addTarget(packageName, userId);
- mImpl.onTargetPackageAdded(packageName, userId);
+ DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
+ return overlay(packageName, targetPackageName, null /* targetOverlayableName */);
}
- /**
- * Begins upgrading the target package.
- *
- * This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast with the
- * {@link android.content.Intent#EXTRA_REPLACING} extra.
- *
- * @throws IllegalStateException if the package is not currently installed
- */
- void beginUpgradeTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed");
- }
- mImpl.onTargetPackageReplacing(packageName, userId);
+ DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
+ String targetOverlayableName) {
+ return new DummyDeviceState.PackageBuilder(packageName, targetPackageName,
+ targetOverlayableName);
}
- /**
- * Ends upgrading the target package.
- *
- * This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
- * {@link android.content.Intent#EXTRA_REPLACING} extra.
- *
- * @throws IllegalStateException if the package is not currently installed
- */
- void endUpgradeTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed");
- }
- mState.addTarget(packageName, userId);
- mImpl.onTargetPackageReplaced(packageName, userId);
+ void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+ mState.add(pkg, userId);
}
- /**
- * Removes the target package from the device.
- *
- * This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast.
- *
- * @throws IllegalStateException if the package is not currently installed
- */
- void uninstallTargetPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed");
- }
- mState.remove(packageName, userId);
- mImpl.onTargetPackageRemoved(packageName, userId);
+ void configureSystemOverlay(String packageName, boolean mutable, boolean enabled,
+ int priority) {
+ when(mOverlayConfig.getPriority(packageName)).thenReturn(priority);
+ when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled);
+ when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable);
}
/**
- * Adds the overlay package to the device.
+ * Adds the package to the device.
*
* This corresponds to when the OMS receives the
* {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast.
*
- * @throws IllegalStateException if the package is already installed
+ * @throws IllegalStateException if the package is currently installed
*/
- void installOverlayPackage(String packageName, String targetPackageName, int userId) {
- if (mState.select(packageName, userId) != null) {
- throw new IllegalStateException("package already installed");
+ void installNewPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+ if (mState.select(pkg.packageName, userId) != null) {
+ throw new IllegalStateException("package " + pkg.packageName + " already installed");
+ }
+ mState.add(pkg, userId);
+ if (pkg.targetPackage == null) {
+ mImpl.onTargetPackageAdded(pkg.packageName, userId);
+ } else {
+ mImpl.onOverlayPackageAdded(pkg.packageName, userId);
}
- mState.addOverlay(packageName, targetPackageName, userId);
- mImpl.onOverlayPackageAdded(packageName, userId);
}
/**
- * Begins upgrading the overlay package.
+ * Begins upgrading the package.
*
* This corresponds to when the OMS receives the
* {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast with the
+ * {@link android.content.Intent#EXTRA_REPLACING} extra and then receives the
+ * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
* {@link android.content.Intent#EXTRA_REPLACING} extra.
*
* @throws IllegalStateException if the package is not currently installed
*/
- void beginUpgradeOverlayPackage(String packageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed, cannot upgrade");
+ void upgradePackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+ final DummyDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
+ if (replacedPackage == null) {
+ throw new IllegalStateException("package " + pkg.packageName + " not installed");
+ }
+ if (replacedPackage.targetPackageName != null) {
+ mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
}
- mImpl.onOverlayPackageReplacing(packageName, userId);
+ mState.add(pkg, userId);
+ if (pkg.targetPackage == null) {
+ mImpl.onTargetPackageReplaced(pkg.packageName, userId);
+ } else {
+ mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
+ }
}
/**
- * Ends upgrading the overlay package, potentially changing its target package.
+ * Removes the package from the device.
*
* This corresponds to when the OMS receives the
- * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
- * {@link android.content.Intent#EXTRA_REPLACING} extra.
+ * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast.
*
* @throws IllegalStateException if the package is not currently installed
*/
- void endUpgradeOverlayPackage(String packageName, String targetPackageName, int userId) {
- if (mState.select(packageName, userId) == null) {
- throw new IllegalStateException("package not installed, cannot upgrade");
+ void uninstallPackage(String packageName, int userId) {
+ final DummyDeviceState.Package pkg = mState.select(packageName, userId);
+ if (pkg == null) {
+ throw new IllegalStateException("package " + packageName+ " not installed");
+ }
+ mState.remove(pkg.packageName);
+ if (pkg.targetPackageName == null) {
+ mImpl.onTargetPackageRemoved(pkg.packageName, userId);
+ } else {
+ mImpl.onOverlayPackageRemoved(pkg.packageName, userId);
}
-
- mState.addOverlay(packageName, targetPackageName, userId);
- mImpl.onOverlayPackageReplaced(packageName, userId);
}
- private static final class DummyDeviceState {
- private List<Package> mPackages = new ArrayList<>();
- private OverlayConfig mOverlayConfig = mock(OverlayConfig.class);
-
- /** Adds a non-overlay to the device. */
- public void addTarget(String packageName, int userId) {
- remove(packageName, userId);
- mPackages.add(new Package(packageName, userId, null, false, false, 0));
- }
-
- /** Adds an overlay to the device. */
- public void addOverlay(String packageName, String targetPackageName, int userId) {
- addOverlay(packageName, targetPackageName, userId, true, false, OverlayConfig.DEFAULT_PRIORITY);
- }
-
- /** Adds a configured overlay to the device. */
- public void addOverlay(String packageName, String targetPackageName, int userId,
- boolean mutable, boolean enabled, int priority) {
- remove(packageName, userId);
- mPackages.add(new Package(packageName, userId, targetPackageName, mutable, enabled,
- priority));
- when(mOverlayConfig.getPriority(packageName)).thenReturn(priority);
- when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled);
- when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable);
- }
-
- /** Remove a package from the device. */
- public void remove(String packageName, int userId) {
- final Iterator<Package> iter = mPackages.iterator();
- while (iter.hasNext()) {
- final Package pkg = iter.next();
- if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
- iter.remove();
- return;
- }
+ /** Represents the state of packages installed on a fake device. */
+ static class DummyDeviceState {
+ private ArrayMap<String, Package> mPackages = new ArrayMap<>();
+
+ void add(PackageBuilder pkgBuilder, int userId) {
+ final Package pkg = pkgBuilder.build();
+ final Package previousPkg = select(pkg.packageName, userId);
+ mPackages.put(pkg.packageName, pkg);
+
+ pkg.installedUserIds.add(userId);
+ if (previousPkg != null) {
+ pkg.installedUserIds.addAll(previousPkg.installedUserIds);
}
}
- /** Retrieves all packages on device for a particular user. */
- public List<Package> select(int userId) {
- return mPackages.stream().filter(p -> p.userId == userId).collect(Collectors.toList());
+ void remove(String packageName) {
+ mPackages.remove(packageName);
+ }
+
+ void uninstall(String packageName, int userId) {
+ final Package pkg = mPackages.get(packageName);
+ if (pkg != null) {
+ pkg.installedUserIds.remove(userId);
+ }
+ }
+
+ List<Package> select(int userId) {
+ return mPackages.values().stream().filter(p -> p.installedUserIds.contains(userId))
+ .collect(Collectors.toList());
+ }
+
+ Package select(String packageName, int userId) {
+ final Package pkg = mPackages.get(packageName);
+ return pkg != null && pkg.installedUserIds.contains(userId) ? pkg : null;
}
- /** Retrieves the package with the specified package name for a particular user. */
- public Package select(String packageName, int userId) {
- return mPackages.stream().filter(
- p -> p.packageName.equals(packageName) && p.userId == userId)
- .findFirst().orElse(null);
+ private Package selectFromPath(String path) {
+ return mPackages.values().stream()
+ .filter(p -> p.apkPath.equals(path)).findFirst().orElse(null);
}
- private static final class Package {
- public final String packageName;
- public final int userId;
- public final String targetPackageName;
- public final boolean mutable;
- public final boolean enabled;
- public final int priority;
+ static final class PackageBuilder {
+ private String packageName;
+ private String targetPackage;
+ private String certificate = "[default]";
+ private int version = 0;
+ private ArrayList<String> overlayableNames = new ArrayList<>();
+ private String targetOverlayableName;
- private Package(String packageName, int userId, String targetPackageName,
- boolean mutable, boolean enabled, int priority) {
+ private PackageBuilder(String packageName, String targetPackage,
+ String targetOverlayableName) {
+ this.packageName = packageName;
+ this.targetPackage = targetPackage;
+ this.targetOverlayableName = targetOverlayableName;
+ }
+
+ PackageBuilder setCertificate(String certificate) {
+ this.certificate = certificate;
+ return this;
+ }
+
+ PackageBuilder addOverlayable(String overlayableName) {
+ overlayableNames.add(overlayableName);
+ return this;
+ }
+
+ PackageBuilder setVersion(int version) {
+ this.version = version;
+ return this;
+ }
+
+ Package build() {
+ final String apkPath = String.format("%s/%s/base.apk",
+ targetPackage == null ? "/system/app/:" : "/vendor/overlay/:",
+ packageName);
+ final Package newPackage = new Package(packageName, targetPackage,
+ targetOverlayableName, version, apkPath, certificate);
+ newPackage.overlayableNames.addAll(overlayableNames);
+ return newPackage;
+ }
+ }
+
+ static final class Package {
+ final String packageName;
+ final String targetPackageName;
+ final String targetOverlayableName;
+ final int versionCode;
+ final String apkPath;
+ final String certificate;
+ final ArrayList<String> overlayableNames = new ArrayList<>();
+ private final ArraySet<Integer> installedUserIds = new ArraySet<>();
+
+ private Package(String packageName, String targetPackageName,
+ String targetOverlayableName, int versionCode, String apkPath,
+ String certificate) {
this.packageName = packageName;
- this.userId = userId;
this.targetPackageName = targetPackageName;
- this.mutable = mutable;
- this.enabled = enabled;
- this.priority = priority;
+ this.targetOverlayableName = targetOverlayableName;
+ this.versionCode = versionCode;
+ this.apkPath = apkPath;
+ this.certificate = certificate;
}
}
}
@@ -288,6 +314,8 @@ class OverlayManagerServiceImplTestsBase {
static final class DummyPackageManagerHelper implements PackageManagerHelper,
OverlayableInfoCallback {
private final DummyDeviceState mState;
+ String[] overlayableConfiguratorTargets = new String[0];
+ String overlayableConfigurator = "";
private DummyPackageManagerHelper(DummyDeviceState state) {
mState = state;
@@ -300,13 +328,12 @@ class OverlayManagerServiceImplTestsBase {
return null;
}
final ApplicationInfo ai = new ApplicationInfo();
- ai.sourceDir = String.format("%s/%s/base.apk",
- pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/",
- pkg.packageName);
+ ai.sourceDir = pkg.apkPath;
PackageInfo pi = new PackageInfo();
pi.applicationInfo = ai;
pi.packageName = pkg.packageName;
pi.overlayTarget = pkg.targetPackageName;
+ pi.targetOverlayableName = pkg.targetOverlayableName;
pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
return pi;
}
@@ -314,14 +341,16 @@ class OverlayManagerServiceImplTestsBase {
@Override
public boolean signaturesMatching(@NonNull String packageName1,
@NonNull String packageName2, int userId) {
- return false;
+ final DummyDeviceState.Package pkg1 = mState.select(packageName1, userId);
+ final DummyDeviceState.Package pkg2 = mState.select(packageName2, userId);
+ return pkg1 != null && pkg2 != null && pkg1.certificate.equals(pkg2.certificate);
}
@Override
public List<PackageInfo> getOverlayPackages(int userId) {
return mState.select(userId).stream()
.filter(p -> p.targetPackageName != null)
- .map(p -> getPackageInfo(p.packageName, p.userId))
+ .map(p -> getPackageInfo(p.packageName, userId))
.collect(Collectors.toList());
}
@@ -329,7 +358,11 @@ class OverlayManagerServiceImplTestsBase {
@Override
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
@NonNull String targetOverlayableName, int userId) {
- throw new UnsupportedOperationException();
+ final DummyDeviceState.Package pkg = mState.select(packageName, userId);
+ if (pkg == null || !pkg.overlayableNames.contains(targetOverlayableName)) {
+ return null;
+ }
+ return new OverlayableInfo(targetOverlayableName, null /* actor */);
}
@Nullable
@@ -341,69 +374,98 @@ class OverlayManagerServiceImplTestsBase {
@NonNull
@Override
public Map<String, Map<String, String>> getNamedActors() {
- throw new UnsupportedOperationException();
+ return Collections.emptyMap();
}
@Override
public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) {
- throw new UnsupportedOperationException();
+ final DummyDeviceState.Package pkg = mState.select(targetPackageName, userId);
+ return pkg != null && pkg.overlayableNames.contains(targetPackageName);
}
@Override
public void enforcePermission(String permission, String message) throws SecurityException {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String[] getOverlayableConfiguratorTargets() {
+ return overlayableConfiguratorTargets;
+ }
+
+ @Override
+ public String getOverlayableConfigurator() {
+ return overlayableConfigurator;
+ }
}
- static class DummyIdmapManager extends IdmapManager {
+ static class DummyIdmapDaemon extends IdmapDaemon {
private final DummyDeviceState mState;
- private Set<String> mIdmapFiles = new ArraySet<>();
+ private final ArrayMap<String, IdmapHeader> mIdmapFiles = new ArrayMap<>();
- private DummyIdmapManager(DummyDeviceState state,
- DummyPackageManagerHelper packageManagerHelper) {
- super(packageManagerHelper);
- mState = state;
+ DummyIdmapDaemon(DummyDeviceState state) {
+ this.mState = state;
+ }
+
+ private int getCrc(@NonNull final String path) {
+ final DummyDeviceState.Package pkg = mState.selectFromPath(path);
+ Assert.assertNotNull(pkg);
+ return pkg.versionCode;
}
@Override
- boolean createIdmap(@NonNull final PackageInfo targetPackage,
- @NonNull final PackageInfo overlayPackage, int userId) {
- final DummyDeviceState.Package t = mState.select(targetPackage.packageName, userId);
- if (t == null) {
- return false;
- }
- final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId);
- if (o == null) {
- return false;
- }
- final String key = createKey(overlayPackage.packageName, userId);
- return mIdmapFiles.add(key);
+ String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+ int userId) {
+ mIdmapFiles.put(overlayPath, new IdmapHeader(getCrc(targetPath),
+ getCrc(overlayPath), targetPath, policies, enforce));
+ return overlayPath;
+ }
+
+ @Override
+ boolean removeIdmap(String overlayPath, int userId) {
+ return mIdmapFiles.remove(overlayPath) != null;
}
@Override
- boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
- final String key = createKey(oi.packageName, oi.userId);
- if (!mIdmapFiles.contains(key)) {
+ boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+ int userId) {
+ final IdmapHeader idmap = mIdmapFiles.get(overlayPath);
+ if (idmap == null) {
return false;
}
- mIdmapFiles.remove(key);
- return true;
+ return idmap.isUpToDate(getCrc(targetPath), getCrc(overlayPath), targetPath);
}
@Override
- boolean idmapExists(@NonNull final OverlayInfo oi) {
- final String key = createKey(oi.packageName, oi.userId);
- return mIdmapFiles.contains(key);
+ boolean idmapExists(String overlayPath, int userId) {
+ return mIdmapFiles.containsKey(overlayPath);
}
- @Override
- boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
- final String key = createKey(overlayPackage.packageName, userId);
- return mIdmapFiles.contains(key);
+ IdmapHeader getIdmap(String overlayPath) {
+ return mIdmapFiles.get(overlayPath);
}
- private String createKey(@NonNull final String packageName, final int userId) {
- return String.format("%s:%d", packageName, userId);
+ static class IdmapHeader {
+ private final int targetCrc;
+ private final int overlayCrc;
+ final String targetPath;
+ final int policies;
+ final boolean enforceOverlayable;
+
+ private IdmapHeader(int targetCrc, int overlayCrc, String targetPath, int policies,
+ boolean enforceOverlayable) {
+ this.targetCrc = targetCrc;
+ this.overlayCrc = overlayCrc;
+ this.targetPath = targetPath;
+ this.policies = policies;
+ this.enforceOverlayable = enforceOverlayable;
+ }
+
+ private boolean isUpToDate(int expectedTargetCrc, int expectedOverlayCrc,
+ String expectedTargetPath) {
+ return expectedTargetCrc == targetCrc && expectedOverlayCrc == overlayCrc
+ && expectedTargetPath.equals(targetPath);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
index 70d6cf81c3b0..c5d94875b684 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
@@ -46,7 +46,8 @@ public final class ConversationInfoTest {
.setContactUri(CONTACT_URI)
.setContactPhoneNumber(PHONE_NUMBER)
.setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
- .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED | ShortcutInfo.FLAG_CACHED)
+ .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
+ | ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
.setImportant(true)
.setNotificationSilenced(true)
.setBubbled(true)
@@ -62,7 +63,7 @@ public final class ConversationInfoTest {
assertEquals(PHONE_NUMBER, conversationInfo.getContactPhoneNumber());
assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
assertTrue(conversationInfo.isShortcutLongLived());
- assertTrue(conversationInfo.isShortcutCached());
+ assertTrue(conversationInfo.isShortcutCachedForNotification());
assertTrue(conversationInfo.isImportant());
assertTrue(conversationInfo.isNotificationSilenced());
assertTrue(conversationInfo.isBubbled());
@@ -84,7 +85,7 @@ public final class ConversationInfoTest {
assertNull(conversationInfo.getContactPhoneNumber());
assertNull(conversationInfo.getNotificationChannelId());
assertFalse(conversationInfo.isShortcutLongLived());
- assertFalse(conversationInfo.isShortcutCached());
+ assertFalse(conversationInfo.isShortcutCachedForNotification());
assertFalse(conversationInfo.isImportant());
assertFalse(conversationInfo.isNotificationSilenced());
assertFalse(conversationInfo.isBubbled());
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 1a2032ac15d0..b2f7abbf84df 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -405,7 +405,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- shortcut.setCached();
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
NotificationListenerService listenerService =
@@ -419,7 +419,8 @@ public final class DataManagerTest {
assertEquals(1, activeNotificationOpenTimeSlots.size());
verify(mShortcutServiceInternal).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
@@ -434,7 +435,7 @@ public final class DataManagerTest {
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
// Post one notification.
- shortcut.setCached();
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
listenerService.onNotificationPosted(mStatusBarNotification);
@@ -445,14 +446,15 @@ public final class DataManagerTest {
listenerService.onNotificationRemoved(mStatusBarNotification, null,
NotificationListenerService.REASON_CANCEL);
verify(mShortcutServiceInternal, never()).uncacheShortcuts(
- anyInt(), any(), anyString(), any(), anyInt());
+ anyInt(), any(), anyString(), any(), anyInt(), anyInt());
// Removing the second notification un-caches the shortcut.
listenerService.onNotificationRemoved(mStatusBarNotification, null,
NotificationListenerService.REASON_CANCEL_ALL);
verify(mShortcutServiceInternal).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
@@ -467,7 +469,7 @@ public final class DataManagerTest {
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
listenerService.onNotificationPosted(mStatusBarNotification);
- shortcut.setCached();
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
@@ -477,7 +479,8 @@ public final class DataManagerTest {
NotificationListenerService.REASON_CANCEL_ALL);
verify(mShortcutServiceInternal, never()).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
@@ -569,13 +572,14 @@ public final class DataManagerTest {
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
listenerService.onNotificationPosted(mStatusBarNotification);
- shortcut.setCached();
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
verify(mShortcutServiceInternal).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
@@ -590,7 +594,7 @@ public final class DataManagerTest {
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
listenerService.onNotificationPosted(mStatusBarNotification);
- shortcut.setCached();
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
@@ -599,7 +603,8 @@ public final class DataManagerTest {
mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
verify(mShortcutServiceInternal, never()).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
@@ -767,14 +772,15 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- shortcut.setCached();
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
verify(mShortcutServiceInternal).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index db02524e6fab..90989b9eda84 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -137,6 +137,9 @@ import java.util.function.BiConsumer;
@SmallTest
public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
+ private static final int CACHE_OWNER_0 = LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS;
+ private static final int CACHE_OWNER_1 = LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS;
+
@Override
protected void tearDown() throws Exception {
deleteUriFile("file32x32.jpg");
@@ -487,7 +490,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
mManager.pushDynamicShortcut(s8);
assertEquals(4, getCallerShortcut("s8").getRank());
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s8"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s8"), HANDLE_USER_0,
+ CACHE_OWNER_0);
});
mManager.pushDynamicShortcut(s9);
@@ -1452,8 +1456,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Cache 1 and 2
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"),
- HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"),
+ HANDLE_USER_0, CACHE_OWNER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"),
+ HANDLE_USER_0, CACHE_OWNER_1);
});
setCaller(CALLING_PACKAGE_1);
@@ -1532,8 +1538,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Cache some, but non long lived shortcuts will be ignored.
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s4"),
- HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"),
+ HANDLE_USER_0, CACHE_OWNER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4"),
+ HANDLE_USER_0, CACHE_OWNER_1);
});
setCaller(CALLING_PACKAGE_1);
@@ -1555,10 +1563,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
"s2", "s4");
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4"),
+ HANDLE_USER_0, CACHE_OWNER_0);
+ });
+ // s2 still cached by owner1. s4 wasn't cached by owner0 so didn't get removed.
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s2", "s4");
+
// uncache a non-dynamic shortcut. Should be removed.
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s4"),
- HANDLE_USER_0);
+ HANDLE_USER_0, CACHE_OWNER_1);
});
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
"s2");
@@ -1566,7 +1582,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Cache another shortcut
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"),
- HANDLE_USER_0);
+ HANDLE_USER_0, CACHE_OWNER_0);
});
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
"s2", "s3");
@@ -1594,7 +1610,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Cache All
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
- HANDLE_USER_0);
+ HANDLE_USER_0, CACHE_OWNER_0);
});
setCaller(CALLING_PACKAGE_1);
@@ -1792,8 +1808,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
setCaller(LAUNCHER_1);
// Cache some shortcuts. Only long lived shortcuts can get cached.
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), getCallingUser());
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_3, list("s3"), getCallingUser());
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), getCallingUser(),
+ CACHE_OWNER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_3, list("s3"), getCallingUser(),
+ CACHE_OWNER_0);
// Cached ones only
assertShortcutIds(assertAllNotKeyFieldsOnly(
@@ -8732,7 +8750,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_0,
filter_any));
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java
index 621966535306..6a2b8e0da2d2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.ComponentName;
+import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutChangeCallback;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
@@ -46,6 +47,9 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
private static final ShortcutQuery QUERY_MATCH_ALL = createShortcutQuery(
ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED);
+ private static final int CACHE_OWNER_0 = LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS;
+ private static final int CACHE_OWNER_1 = LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS;
+
private final TestLooper mTestLooper = new TestLooper();
public void testShortcutChangeCallback_setDynamicShortcuts() {
@@ -113,7 +117,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
});
ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
@@ -211,7 +216,42 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0,
+ CACHE_OWNER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0,
+ CACHE_OWNER_1);
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(2)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s3");
+ }
+
+ public void testShortcutChangeCallback_cacheShortcuts_alreadyCached() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0,
+ CACHE_OWNER_0);
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ // Should not cause any callback events
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0,
+ CACHE_OWNER_0);
+ // Should cause a change event
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0,
+ CACHE_OWNER_1);
});
mTestLooper.dispatchAll();
@@ -234,10 +274,12 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
- mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
});
mTestLooper.dispatchAll();
@@ -259,8 +301,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
});
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0,
+ CACHE_OWNER_1);
});
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -271,7 +316,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
- mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0);
+ mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0,
+ CACHE_OWNER_0);
});
mTestLooper.dispatchAll();
@@ -284,9 +330,10 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
verify(callback, times(1)).onShortcutsRemoved(
eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+ // s1 is still cached for owner1, s2 is pinned.
assertWith(changedShortcuts.getValue())
.areAllWithKeyFieldsOnly()
- .haveIds("s2");
+ .haveIds("s1", "s2");
assertWith(removedShortcuts.getValue())
.areAllWithKeyFieldsOnly()
@@ -453,7 +500,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
});
@@ -511,7 +559,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
@@ -547,7 +596,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
});
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
});
@@ -614,7 +664,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
@@ -680,7 +731,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
@@ -747,7 +799,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0,
+ CACHE_OWNER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
mTestLooper.getNewExecutor());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
index 38b71b707196..13457f0a284c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
@@ -26,6 +26,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -166,6 +168,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
ALLOW_BUBBLE_OFF /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -178,6 +182,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
DEFAULT_ALLOW_BUBBLE /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -190,6 +196,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -202,6 +210,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(false /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -215,6 +225,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_NONE /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -228,6 +240,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_NONE /* app */,
DEFAULT_ALLOW_BUBBLE /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -241,6 +255,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
DEFAULT_ALLOW_BUBBLE /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -254,6 +270,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
ALLOW_BUBBLE_OFF /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -267,6 +285,9 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
+
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -279,6 +300,9 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(false /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
+
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -305,6 +329,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
assertTrue(r.canBubble());
+ assertNotNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -320,6 +345,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
assertTrue(r.canBubble());
+ assertNotNull(r.getNotification().getBubbleMetadata());
assertTrue(r.getNotification().isBubbleNotification());
}
@@ -335,6 +361,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
assertTrue(r.canBubble());
+ assertNotNull(r.getNotification().getBubbleMetadata());
assertTrue(r.getNotification().isBubbleNotification());
}
@@ -350,7 +377,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
r.setShortcutInfo(null);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -366,7 +394,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
r.setShortcutInfo(null);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -381,7 +410,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -395,7 +425,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(false /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -414,7 +445,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -429,7 +461,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -445,7 +478,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -462,7 +496,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ced780475fb7..cf636823d5f7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6135,8 +6135,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
"tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
-
// Test: Send the bubble notification
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
@@ -6154,7 +6152,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Make sure the shortcut is cached.
verify(mShortcutServiceInternal).cacheShortcuts(
anyInt(), any(), eq(PKG), eq(Collections.singletonList(VALID_CONVO_SHORTCUT_ID)),
- eq(USER_SYSTEM));
+ eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
// Test: Remove the shortcut
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
@@ -6168,12 +6166,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
// We're no longer a bubble
- Notification notif2 = mService.getNotificationRecord(
- nr.getSbn().getKey()).getNotification();
- assertFalse(notif2.isBubbleNotification());
+ NotificationRecord notif2 = mService.getNotificationRecord(
+ nr.getSbn().getKey());
+ assertNull(notif2.getShortcutInfo());
+ assertFalse(notif2.getNotification().isBubbleNotification());
}
-
@Test
public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved()
throws RemoteException {
@@ -6227,7 +6225,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Make sure the shortcut is cached.
verify(mShortcutServiceInternal).cacheShortcuts(
anyInt(), any(), eq(PKG), eq(Collections.singletonList(shortcutId)),
- eq(USER_SYSTEM));
+ eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
// Test: Remove the notification
mBinderService.cancelNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 078c21e04512..1d6f8233b7b4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -31,6 +31,7 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
+import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID;
import static com.google.common.truth.Truth.assertThat;
@@ -2511,6 +2512,26 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ public void testBubblePrefence_noSAWCheckForUnknownUid() throws Exception {
+ final String xml = "<ranking version=\"1\">\n"
+ + "<package name=\"" + PKG_O + "\" uid=\"" + UNKNOWN_UID + "\">\n"
+ + "<channel id=\"someId\" name=\"hi\""
+ + " importance=\"3\"/>"
+ + "</package>"
+ + "</ranking>";
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
+ null);
+ parser.nextTag();
+ mHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ assertEquals(DEFAULT_BUBBLE_PREFERENCE, mHelper.getBubblePreference(PKG_O, UID_O));
+ assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
+ verify(mAppOpsManager, never()).noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
+ anyString(), eq(null), anyString());
+ }
+
+ @Test
public void testBubblePreference_xml() throws Exception {
mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index eb2d9fed197f..c700a090fa2e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -48,6 +48,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
@SmallTest
@@ -73,6 +74,8 @@ public class ShortcutHelperTest extends UiServiceTestCase {
StatusBarNotification mSbn;
@Mock
Notification.BubbleMetadata mBubbleMetadata;
+ @Mock
+ ShortcutInfo mShortcutInfo;
ShortcutHelper mShortcutHelper;
@@ -86,13 +89,13 @@ public class ShortcutHelperTest extends UiServiceTestCase {
when(mNr.getSbn()).thenReturn(mSbn);
when(mSbn.getPackageName()).thenReturn(PKG);
when(mNr.getNotification()).thenReturn(mNotif);
+ when(mNr.getShortcutInfo()).thenReturn(mShortcutInfo);
+ when(mShortcutInfo.getId()).thenReturn(SHORTCUT_ID);
when(mNotif.getBubbleMetadata()).thenReturn(mBubbleMetadata);
when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID);
}
private LauncherApps.Callback addShortcutBubbleAndVerifyListener() {
- when(mNotif.isBubbleNotification()).thenReturn(true);
-
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
false /* removed */,
null /* handler */);
@@ -124,12 +127,40 @@ public class ShortcutHelperTest extends UiServiceTestCase {
}
@Test
- public void testBubbleNoLongerBubble_listenerRemoved() {
+ public void testBubbleNoLongerHasBubbleMetadata_listenerRemoved() {
// First set it up to listen
addShortcutBubbleAndVerifyListener();
// Then make it not a bubble
- when(mNotif.isBubbleNotification()).thenReturn(false);
+ when(mNotif.getBubbleMetadata()).thenReturn(null);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
+ false /* removed */,
+ null /* handler */);
+
+ verify(mLauncherApps, times(1)).unregisterCallback(any());
+ }
+
+ @Test
+ public void testBubbleNoLongerHasShortcutId_listenerRemoved() {
+ // First set it up to listen
+ addShortcutBubbleAndVerifyListener();
+
+ // Clear out shortcutId
+ when(mBubbleMetadata.getShortcutId()).thenReturn(null);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
+ false /* removed */,
+ null /* handler */);
+
+ verify(mLauncherApps, times(1)).unregisterCallback(any());
+ }
+
+ @Test
+ public void testNotifNoLongerHasShortcut_listenerRemoved() {
+ // First set it up to listen
+ addShortcutBubbleAndVerifyListener();
+
+ // Clear out shortcutId
+ when(mNr.getShortcutInfo()).thenReturn(null);
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
false /* removed */,
null /* handler */);
@@ -138,6 +169,17 @@ public class ShortcutHelperTest extends UiServiceTestCase {
}
@Test
+ public void testOnShortcutsChanged_listenerRemoved() {
+ // First set it up to listen
+ LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();
+
+ // App shortcuts are removed:
+ callback.onShortcutsChanged(PKG, Collections.emptyList(), mock(UserHandle.class));
+
+ verify(mLauncherApps, times(1)).unregisterCallback(any());
+ }
+
+ @Test
public void testListenerNotifiedOnShortcutRemoved() {
LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 4e82ceb882a8..d063f10d52e2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -57,6 +57,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -1060,6 +1061,11 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testApplyTopFixedRotationTransform() {
mWm.mIsFixedRotationTransformEnabled = true;
+ final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+ // Only non-movable (gesture) navigation bar will be animated by fixed rotation animation.
+ doReturn(false).when(displayPolicy).navigationBarCanMove();
+ displayPolicy.addWindowLw(mStatusBarWindow, mStatusBarWindow.mAttrs);
+ displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
final Configuration config90 = new Configuration();
mDisplayContent.computeScreenConfiguration(config90, ROTATION_90);
@@ -1080,6 +1086,12 @@ public class DisplayContentTests extends WindowTestsBase {
ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
false /* forceUpdate */));
+ assertNotNull(mDisplayContent.getFixedRotationAnimationController());
+ assertTrue(mStatusBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
+ ANIMATION_TYPE_FIXED_TRANSFORM));
+ assertTrue(mNavBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
+ ANIMATION_TYPE_FIXED_TRANSFORM));
+
final Rect outFrame = new Rect();
final Rect outInsets = new Rect();
final Rect outStableInsets = new Rect();
@@ -1132,6 +1144,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertFalse(app.hasFixedRotationTransform());
assertFalse(app2.hasFixedRotationTransform());
assertEquals(config90.orientation, mDisplayContent.getConfiguration().orientation);
+ assertNull(mDisplayContent.getFixedRotationAnimationController());
}
@Test
@@ -1310,7 +1323,7 @@ public class DisplayContentTests extends WindowTestsBase {
}
private static int getRotatedOrientation(DisplayContent dc) {
- return dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
+ return dc.mBaseDisplayWidth > dc.mBaseDisplayHeight
? SCREEN_ORIENTATION_PORTRAIT
: SCREEN_ORIENTATION_LANDSCAPE;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index e47792f4920c..68bc58493f13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -138,7 +138,7 @@ public class SizeCompatTests extends ActivityTestsBase {
// Rotation is ignored so because the display size is close to square (700/600<1.333).
assertTrue(mActivity.mDisplayContent.ignoreRotationForApps());
- final Rect displayBounds = mActivity.mDisplayContent.getBounds();
+ final Rect displayBounds = mActivity.mDisplayContent.getWindowConfiguration().getBounds();
final float aspectRatio = 1.2f;
mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = aspectRatio;
prepareUnresizable(-1f, SCREEN_ORIENTATION_UNSPECIFIED);
@@ -160,13 +160,22 @@ public class SizeCompatTests extends ActivityTestsBase {
assertFitted();
// After the orientation of activity is changed, even display is not rotated, the aspect
- // ratio should be the same (bounds=[0, 0 - 600, 600], appBounds=[0, 100 - 600, 600]).
+ // ratio should be the same (appBounds=[9, 100 - 592, 800], x-offset=round((600-583)/2)=9).
assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
// The notch is still on top.
assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertFitted();
+
+ // Close-to-square display can rotate without being restricted by the requested orientation.
+ // The notch becomes on the left side. The activity is horizontal centered in 100 ~ 800.
+ // So the bounds and appBounds will be [200, 0 - 700, 600] (500x600) that is still fitted.
+ // Left = 100 + (800 - 100 - 500) / 2 = 200.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+ assertFitted();
+ assertEquals(appBounds.left,
+ notchHeight + (displayBounds.width() - notchHeight - appBounds.width()) / 2);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 8ce5daa635f2..e9ed20bd9683 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -603,6 +603,29 @@ public class WindowStateTests extends WindowTestsBase {
}
@Test
+ public void testRequestResizeForBlastSync() {
+ final WindowState win = mChildAppWindowAbove;
+ makeWindowVisible(win, win.getParentWindow());
+ win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
+ win.reportResized();
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).doesNotContain(win);
+
+ // Check that the window is in resizing if using blast sync.
+ win.reportResized();
+ win.prepareForSync(mock(BLASTSyncEngine.TransactionReadyListener.class), 1);
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).contains(win);
+
+ // Don't re-add the window again if it's been reported to the client and still waiting on
+ // the client draw for blast sync.
+ win.reportResized();
+ mWm.mResizingWindows.remove(win);
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).doesNotContain(win);
+ }
+
+ @Test
public void testGetTransformationMatrix() {
final int PARENT_WINDOW_OFFSET = 1;
final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2;