diff options
Diffstat (limited to 'services')
40 files changed, 1611 insertions, 477 deletions
diff --git a/services/Android.bp b/services/Android.bp index b51e4b014b27..da24719c0f68 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -30,6 +30,7 @@ filegroup { ":services.searchui-sources", ":services.startop.iorap-sources", ":services.systemcaptions-sources", + ":services.translation-sources", ":services.usage-sources", ":services.usb-sources", ":services.voiceinteraction-sources", @@ -76,6 +77,7 @@ java_library { "services.searchui", "services.startop", "services.systemcaptions", + "services.translation", "services.usage", "services.usb", "services.voiceinteraction", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 397eeb23396c..020c17a77084 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -620,7 +620,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private LingerMonitor mLingerMonitor; // sequence number of NetworkRequests - private int mNextNetworkRequestId = 1; + private int mNextNetworkRequestId = NetworkRequest.FIRST_REQUEST_ID; // Sequence number for NetworkProvider IDs. private final AtomicInteger mNextNetworkProviderId = new AtomicInteger( @@ -1238,6 +1238,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } private synchronized int nextNetworkRequestId() { + // TODO: Consider handle wrapping and exclude {@link NetworkRequest#REQUEST_ID_NONE} if + // doing that. return mNextNetworkRequestId++; } @@ -1329,15 +1331,20 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Check if UID should be blocked from using the specified network. */ - private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, - boolean ignoreBlocked) { + private boolean isNetworkWithCapabilitiesBlocked(@Nullable final NetworkCapabilities nc, + final int uid, final boolean ignoreBlocked) { // Networks aren't blocked when ignoring blocked status if (ignoreBlocked) { return false; } if (isUidBlockedByVpn(uid, mVpnBlockedUidRanges)) return true; - final String iface = (lp == null ? "" : lp.getInterfaceName()); - return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface); + final long ident = Binder.clearCallingIdentity(); + try { + final boolean metered = nc == null ? true : nc.isMetered(); + return mPolicyManager.isUidNetworkingBlocked(uid, metered); + } finally { + Binder.restoreCallingIdentity(ident); + } } private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { @@ -1375,12 +1382,13 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Apply any relevant filters to {@link NetworkState} for the given UID. For * example, this may mark the network as {@link DetailedState#BLOCKED} based - * on {@link #isNetworkWithLinkPropertiesBlocked}. + * on {@link #isNetworkWithCapabilitiesBlocked}. */ private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) { if (state == null || state.networkInfo == null || state.linkProperties == null) return; - if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) { + if (isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid, + ignoreBlocked)) { state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null); } synchronized (mVpns) { @@ -1440,8 +1448,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } nai = getDefaultNetwork(); - if (nai != null - && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, ignoreBlocked)) { + if (nai != null && isNetworkWithCapabilitiesBlocked( + nai.networkCapabilities, uid, ignoreBlocked)) { nai = null; } return nai != null ? nai.network : null; @@ -1513,7 +1521,7 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); final int uid = mDeps.getCallingUid(); NetworkState state = getFilteredNetworkState(networkType, uid); - if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) { + if (!isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid, false)) { return state.network; } return null; @@ -4471,7 +4479,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!nai.everConnected) { return; } - if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) { + final NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai); + if (isNetworkWithCapabilitiesBlocked(nc, uid, false)) { return; } nai.networkMonitor().forceReevaluation(uid); @@ -7065,11 +7074,11 @@ public class ConnectivityService extends IConnectivityManager.Stub log(" accepting network in place of " + previousSatisfier.toShortString()); } previousSatisfier.removeRequest(nri.request.requestId); - previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs); + previousSatisfier.lingerRequest(nri.request.requestId, now, mLingerDelayMs); } else { if (VDBG || DDBG) log(" accepting network in place of null"); } - newSatisfier.unlingerRequest(nri.request); + newSatisfier.unlingerRequest(nri.request.requestId); if (!newSatisfier.addRequest(nri.request)) { Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has " + nri.request); diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 99a1d86d244e..8b506bac4a85 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -54,9 +54,13 @@ import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParserException; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; @@ -149,6 +153,11 @@ public class PackageWatchdog { private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check"; private static final String ATTR_MITIGATION_CALLS = "mitigation-calls"; + // A file containing information about the current mitigation count in the case of a boot loop. + // This allows boot loop information to persist in the case of an fs-checkpoint being + // aborted. + private static final String METADATA_FILE = "/metadata/watchdog/mitigation_count.txt"; + @GuardedBy("PackageWatchdog.class") private static PackageWatchdog sPackageWatchdog; @@ -492,6 +501,7 @@ public class PackageWatchdog { } if (currentObserverToNotify != null) { mBootThreshold.setMitigationCount(mitigationCount); + mBootThreshold.saveMitigationCountToMetadata(); currentObserverToNotify.executeBootLoopMitigation(mitigationCount); } } @@ -1700,9 +1710,31 @@ public class PackageWatchdog { SystemProperties.set(property, Long.toString(newStart)); } + public void saveMitigationCountToMetadata() { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(METADATA_FILE))) { + writer.write(String.valueOf(getMitigationCount())); + } catch (Exception e) { + Slog.e(TAG, "Could not save metadata to file: " + e); + } + } + + public void readMitigationCountFromMetadataIfNecessary() { + File bootPropsFile = new File(METADATA_FILE); + if (bootPropsFile.exists()) { + try (BufferedReader reader = new BufferedReader(new FileReader(METADATA_FILE))) { + String mitigationCount = reader.readLine(); + setMitigationCount(Integer.parseInt(mitigationCount)); + bootPropsFile.delete(); + } catch (Exception e) { + Slog.i(TAG, "Could not read metadata file: " + e); + } + } + } + /** Increments the boot counter, and returns whether the device is bootlooping. */ public boolean incrementAndTest() { + readMitigationCountFromMetadataIfNecessary(); final long now = mSystemClock.uptimeMillis(); if (now - getStart() < 0) { Slog.e(TAG, "Window was less than zero. Resetting start to current time."); diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index a1cf8162f0e9..db36e62e44a3 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -31,6 +31,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; +import android.os.PowerManager; import android.os.RecoverySystem; import android.os.RemoteCallback; import android.os.SystemClock; @@ -77,6 +78,7 @@ public class RescueParty { @VisibleForTesting static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue"; static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset"; + static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot"; static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted"; @VisibleForTesting static final int LEVEL_NONE = 0; @@ -87,7 +89,9 @@ public class RescueParty { @VisibleForTesting static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3; @VisibleForTesting - static final int LEVEL_FACTORY_RESET = 4; + static final int LEVEL_WARM_REBOOT = 4; + @VisibleForTesting + static final int LEVEL_FACTORY_RESET = 5; @VisibleForTesting static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count"; @VisibleForTesting @@ -159,12 +163,24 @@ public class RescueParty { } /** - * Check if we're currently attempting to reboot for a factory reset. + * Check if we're currently attempting to reboot for a factory reset. This method must + * return true if RescueParty tries to reboot early during a boot loop, since the device + * will not be fully booted at this time. + * + * TODO(gavincorkery): Rename method since its scope has expanded. */ public static boolean isAttemptingFactoryReset() { + return isFactoryResetPropertySet() || isRebootPropertySet(); + } + + static boolean isFactoryResetPropertySet() { return SystemProperties.getBoolean(PROP_ATTEMPTING_FACTORY_RESET, false); } + static boolean isRebootPropertySet() { + return SystemProperties.getBoolean(PROP_ATTEMPTING_REBOOT, false); + } + /** * Called when {@code SettingsProvider} has been published, which is a good * opportunity to reset any settings depending on our rescue level. @@ -329,8 +345,10 @@ public class RescueParty { return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES; } else if (mitigationCount == 3) { return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS; - } else if (mitigationCount >= 4) { - return getMaxRescueLevel(); + } else if (mitigationCount == 4) { + return Math.min(getMaxRescueLevel(), LEVEL_WARM_REBOOT); + } else if (mitigationCount >= 5) { + return Math.min(getMaxRescueLevel(), LEVEL_FACTORY_RESET); } else { Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount); return LEVEL_NONE; @@ -356,6 +374,8 @@ public class RescueParty { // Try our best to reset all settings possible, and once finished // rethrow any exception that we encountered Exception res = null; + Runnable runnable; + Thread thread; switch (level) { case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: try { @@ -396,11 +416,26 @@ public class RescueParty { res = e; } break; - case LEVEL_FACTORY_RESET: + case LEVEL_WARM_REBOOT: // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog // when device shutting down. + SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true"); + runnable = () -> { + try { + PowerManager pm = context.getSystemService(PowerManager.class); + if (pm != null) { + pm.reboot(TAG); + } + } catch (Throwable t) { + logRescueException(level, t); + } + }; + thread = new Thread(runnable); + thread.start(); + break; + case LEVEL_FACTORY_RESET: SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true"); - Runnable runnable = new Runnable() { + runnable = new Runnable() { @Override public void run() { try { @@ -410,7 +445,7 @@ public class RescueParty { } } }; - Thread thread = new Thread(runnable); + thread = new Thread(runnable); thread.start(); break; } @@ -433,6 +468,7 @@ public class RescueParty { case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return PackageHealthObserverImpact.USER_IMPACT_LOW; case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: + case LEVEL_WARM_REBOOT: case LEVEL_FACTORY_RESET: return PackageHealthObserverImpact.USER_IMPACT_HIGH; default: @@ -714,6 +750,7 @@ public class RescueParty { case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS"; case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES"; case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS"; + case LEVEL_WARM_REBOOT: return "WARM_REBOOT"; case LEVEL_FACTORY_RESET: return "FACTORY_RESET"; default: return Integer.toString(level); } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index b0f2e24e3be2..c951fd438b78 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1716,7 +1716,7 @@ class StorageManagerService extends IStorageManager.Stub public StorageManagerService(Context context) { sSelf = this; mVoldAppDataIsolationEnabled = SystemProperties.getBoolean( - ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); + ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); mContext = context; mResolver = mContext.getContentResolver(); mCallbacks = new Callbacks(FgThread.get().getLooper()); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 53d75d1ddd06..6f6cad043a42 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -711,7 +711,7 @@ public final class ProcessList { mAppDataIsolationEnabled = SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); mVoldAppDataIsolationEnabled = SystemProperties.getBoolean( - ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); + ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); mAppDataIsolationWhitelistedApps = new ArrayList<>( SystemConfig.getInstance().getAppDataIsolationWhitelistedApps()); diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index 18907a19f96d..9ba957ef27ae 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -64,7 +64,7 @@ public final class CompatChange extends CompatibilityChangeInfo { private Map<String, Boolean> mDeferredOverrides; public CompatChange(long changeId) { - this(changeId, null, -1, -1, false, false, null); + this(changeId, null, -1, -1, false, false, null, false); } /** @@ -77,9 +77,10 @@ public final class CompatChange extends CompatibilityChangeInfo { * @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set. */ public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk, - int enableSinceTargetSdk, boolean disabled, boolean loggingOnly, String description) { + int enableSinceTargetSdk, boolean disabled, boolean loggingOnly, String description, + boolean overridable) { super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly, - description); + description, overridable); } /** @@ -88,7 +89,7 @@ public final class CompatChange extends CompatibilityChangeInfo { public CompatChange(Change change) { super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(), change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(), - change.getDescription()); + change.getDescription(), change.getOverridable()); } void registerListener(ChangeListener listener) { @@ -274,6 +275,9 @@ public final class CompatChange extends CompatibilityChangeInfo { if (mDeferredOverrides != null && mDeferredOverrides.size() > 0) { sb.append("; deferredOverrides=").append(mDeferredOverrides); } + if (getOverridable()) { + sb.append("; overridable"); + } return sb.append(")").toString(); } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 7bde4d5a2770..55d8279a92d0 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -202,28 +202,28 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // either the linger timeout expiring and the network being taken down, or the network // satisfying a request again. public static class LingerTimer implements Comparable<LingerTimer> { - public final NetworkRequest request; + public final int requestId; public final long expiryMs; - public LingerTimer(NetworkRequest request, long expiryMs) { - this.request = request; + public LingerTimer(int requestId, long expiryMs) { + this.requestId = requestId; this.expiryMs = expiryMs; } public boolean equals(Object o) { if (!(o instanceof LingerTimer)) return false; LingerTimer other = (LingerTimer) o; - return (request.requestId == other.request.requestId) && (expiryMs == other.expiryMs); + return (requestId == other.requestId) && (expiryMs == other.expiryMs); } public int hashCode() { - return Objects.hash(request.requestId, expiryMs); + return Objects.hash(requestId, expiryMs); } public int compareTo(LingerTimer other) { return (expiryMs != other.expiryMs) ? Long.compare(expiryMs, other.expiryMs) : - Integer.compare(request.requestId, other.request.requestId); + Integer.compare(requestId, other.requestId); } public String toString() { - return String.format("%s, expires %dms", request.toString(), + return String.format("%s, expires %dms", requestId, expiryMs - SystemClock.elapsedRealtime()); } } @@ -693,7 +693,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { updateRequestCounts(REMOVE, existing); mNetworkRequests.remove(requestId); if (existing.isRequest()) { - unlingerRequest(existing); + unlingerRequest(existing.requestId); } } @@ -839,33 +839,33 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } /** - * Sets the specified request to linger on this network for the specified time. Called by + * Sets the specified requestId to linger on this network for the specified time. Called by * ConnectivityService when the request is moved to another network with a higher score. */ - public void lingerRequest(NetworkRequest request, long now, long duration) { - if (mLingerTimerForRequest.get(request.requestId) != null) { + public void lingerRequest(int requestId, long now, long duration) { + if (mLingerTimerForRequest.get(requestId) != null) { // Cannot happen. Once a request is lingering on a particular network, we cannot // re-linger it unless that network becomes the best for that request again, in which // case we should have unlingered it. - Log.wtf(TAG, toShortString() + ": request " + request.requestId + " already lingered"); + Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered"); } final long expiryMs = now + duration; - LingerTimer timer = new LingerTimer(request, expiryMs); + LingerTimer timer = new LingerTimer(requestId, expiryMs); if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + toShortString()); mLingerTimers.add(timer); - mLingerTimerForRequest.put(request.requestId, timer); + mLingerTimerForRequest.put(requestId, timer); } /** * Cancel lingering. Called by ConnectivityService when a request is added to this network. - * Returns true if the given request was lingering on this network, false otherwise. + * Returns true if the given requestId was lingering on this network, false otherwise. */ - public boolean unlingerRequest(NetworkRequest request) { - LingerTimer timer = mLingerTimerForRequest.get(request.requestId); + public boolean unlingerRequest(int requestId) { + LingerTimer timer = mLingerTimerForRequest.get(requestId); if (timer != null) { if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + toShortString()); mLingerTimers.remove(timer); - mLingerTimerForRequest.remove(request.requestId); + mLingerTimerForRequest.remove(requestId); return true; } return false; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 07a4b89be4e9..b250f164a264 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1850,34 +1850,6 @@ public class Vpn { } } - /** - * @param uid The target uid. - * - * @return {@code true} if {@code uid} is included in one of the mBlockedUidsAsToldToNetd - * ranges and the VPN is not connected, or if the VPN is connected but does not apply to - * the {@code uid}. - * - * @apiNote This method don't check VPN lockdown status. - * @see #mBlockedUidsAsToldToConnectivity - */ - public synchronized boolean isBlockingUid(int uid) { - if (mNetworkInfo.isConnected()) { - return !appliesToUid(uid); - } else { - return containsUid(mBlockedUidsAsToldToConnectivity, uid); - } - } - - private boolean containsUid(Collection<UidRangeParcel> ranges, int uid) { - if (ranges == null) return false; - for (UidRangeParcel range : ranges) { - if (range.start <= uid && uid <= range.stop) { - return true; - } - } - return false; - } - private void updateAlwaysOnNotification(DetailedState networkState) { final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 407cedf38917..141fa6a17873 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -44,12 +44,6 @@ public abstract class NetworkPolicyManagerInternal { public abstract boolean isUidRestrictedOnMeteredNetworks(int uid); /** - * @return true if networking is blocked on the given interface for the given uid according - * to current networking policies. - */ - public abstract boolean isUidNetworkingBlocked(int uid, String ifname); - - /** * Figure out if networking is blocked for a given set of conditions. * * This is used by ConnectivityService via passing stale copies of conditions, so it must not diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 0e7b4b8c9c5e..7c17356fa3cc 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -5352,7 +5352,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) { final long startTime = mStatLogger.getTime(); - mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG); + enforceAnyPermissionOf(OBSERVE_NETWORK_POLICY, PERMISSION_MAINLINE_NETWORK_STACK); final int uidRules; final boolean isBackgroundRestricted; synchronized (mUidRulesFirstLock) { @@ -5451,32 +5451,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED); } - /** - * @return true if networking is blocked on the given interface for the given uid according - * to current networking policies. - */ - @Override - public boolean isUidNetworkingBlocked(int uid, String ifname) { - final long startTime = mStatLogger.getTime(); - - final int uidRules; - final boolean isBackgroundRestricted; - synchronized (mUidRulesFirstLock) { - uidRules = mUidRules.get(uid, RULE_NONE); - isBackgroundRestricted = mRestrictBackground; - } - final boolean isNetworkMetered; - synchronized (mMeteredIfacesLock) { - isNetworkMetered = mMeteredIfaces.contains(ifname); - } - final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered, - isBackgroundRestricted, mLogger); - - mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime); - - return ret; - } - @Override public void onTempPowerSaveWhitelistChange(int appId, boolean added) { synchronized (mUidRulesFirstLock) { 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 9088d7b481a5..d65661771a84 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -138,7 +138,6 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BinderCallsStats.ExportedCallStat; -import com.android.internal.os.KernelCpuSpeedReader; import com.android.internal.os.KernelCpuThreadReader; import com.android.internal.os.KernelCpuThreadReaderDiff; import com.android.internal.os.KernelCpuThreadReaderSettingsObserver; @@ -301,8 +300,6 @@ public class StatsPullAtomService extends SystemService { @GuardedBy("mDiskIoLock") private StoragedUidIoStatsReader mStoragedUidIoStatsReader; - @GuardedBy("mCpuTimePerFreqLock") - private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; // Disables throttler on CPU time readers. @GuardedBy("mCpuTimePerUidLock") private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader; @@ -353,7 +350,6 @@ public class StatsPullAtomService extends SystemService { private final Object mDataBytesTransferLock = new Object(); private final Object mBluetoothBytesTransferLock = new Object(); private final Object mKernelWakelockLock = new Object(); - private final Object mCpuTimePerFreqLock = new Object(); private final Object mCpuTimePerUidLock = new Object(); private final Object mCpuTimePerUidFreqLock = new Object(); private final Object mCpuActiveTimeLock = new Object(); @@ -442,10 +438,6 @@ public class StatsPullAtomService extends SystemService { synchronized (mKernelWakelockLock) { return pullKernelWakelockLocked(atomTag, data); } - case FrameworkStatsLog.CPU_TIME_PER_FREQ: - synchronized (mCpuTimePerFreqLock) { - return pullCpuTimePerFreqLocked(atomTag, data); - } case FrameworkStatsLog.CPU_TIME_PER_UID: synchronized (mCpuTimePerUidLock) { return pullCpuTimePerUidLocked(atomTag, data); @@ -722,18 +714,6 @@ public class StatsPullAtomService extends SystemService { mKernelWakelockReader = new KernelWakelockReader(); mTmpWakelockStats = new KernelWakelockStats(); - // Initialize state for CPU_TIME_PER_FREQ atom - PowerProfile powerProfile = new PowerProfile(mContext); - final int numClusters = powerProfile.getNumCpuClusters(); - mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; - int firstCpuOfCluster = 0; - for (int i = 0; i < numClusters; i++) { - final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i); - mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster, - numSpeedSteps); - firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i); - } - // Used for CPU_TIME_PER_THREAD_FREQ mKernelCpuThreadReader = KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext); @@ -793,7 +773,6 @@ public class StatsPullAtomService extends SystemService { mStatsCallbackImpl = new StatsPullAtomCallbackImpl(); registerBluetoothBytesTransfer(); registerKernelWakelock(); - registerCpuTimePerFreq(); registerCpuTimePerUid(); registerCpuCyclesPerUidCluster(); registerCpuTimePerUidFreq(); @@ -1465,32 +1444,6 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } - private void registerCpuTimePerFreq() { - int tagId = FrameworkStatsLog.CPU_TIME_PER_FREQ; - PullAtomMetadata metadata = new PullAtomMetadata.Builder() - .setAdditiveFields(new int[] {3}) - .build(); - mStatsManager.setPullAtomCallback( - tagId, - metadata, - DIRECT_EXECUTOR, - mStatsCallbackImpl - ); - } - - int pullCpuTimePerFreqLocked(int atomTag, List<StatsEvent> pulledData) { - for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { - long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute(); - if (clusterTimeMs != null) { - for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) { - pulledData.add(FrameworkStatsLog.buildStatsEvent( - atomTag, cluster, speed, clusterTimeMs[speed])); - } - } - } - return StatsManager.PULL_SUCCESS; - } - private void registerCpuTimePerUid() { int tagId = FrameworkStatsLog.CPU_TIME_PER_UID; PullAtomMetadata metadata = new PullAtomMetadata.Builder() diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index 865571e90338..d0c632350270 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -18,6 +18,8 @@ package com.android.server.timezonedetector; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.ActivityManager; import android.app.time.ITimeZoneDetectorListener; import android.app.time.TimeZoneCapabilitiesAndConfig; import android.app.time.TimeZoneConfiguration; @@ -26,12 +28,14 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.content.Context; import android.location.LocationManager; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemProperties; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -163,9 +167,13 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub @Override @NonNull public TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig() { + int userId = mCallerIdentityInjector.getCallingUserId(); + return getCapabilitiesAndConfig(userId); + } + + TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig(@UserIdInt int userId) { enforceManageTimeZoneDetectorPermission(); - int userId = mCallerIdentityInjector.getCallingUserId(); final long token = mCallerIdentityInjector.clearCallingIdentity(); try { ConfigurationInternal configurationInternal = @@ -178,13 +186,22 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub @Override public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) { + int callingUserId = mCallerIdentityInjector.getCallingUserId(); + return updateConfiguration(callingUserId, configuration); + } + + boolean updateConfiguration( + @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) { + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), + userId, false, false, "updateConfiguration", null); + enforceManageTimeZoneDetectorPermission(); + Objects.requireNonNull(configuration); - int callingUserId = mCallerIdentityInjector.getCallingUserId(); final long token = mCallerIdentityInjector.clearCallingIdentity(); try { - return mTimeZoneDetectorStrategy.updateConfiguration(callingUserId, configuration); + return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration); } finally { mCallerIdentityInjector.restoreCallingIdentity(token); } @@ -318,11 +335,17 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub return isGeoLocationTimeZoneDetectionEnabled(mContext); } - boolean isLocationEnabled() { + boolean isLocationEnabled(@UserIdInt int userId) { enforceManageTimeZoneDetectorPermission(); - return mContext.getSystemService(LocationManager.class) - .isLocationEnabledForUser(mContext.getUser()); + final long token = mCallerIdentityInjector.clearCallingIdentity(); + try { + UserHandle user = UserHandle.of(userId); + LocationManager locationManager = mContext.getSystemService(LocationManager.class); + return locationManager.isLocationEnabledForUser(user); + } finally { + mCallerIdentityInjector.restoreCallingIdentity(token); + } } @Override diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java index b2630300a6aa..e965f55e49d7 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java @@ -29,6 +29,7 @@ import android.app.time.TimeZoneConfiguration; import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.os.ShellCommand; +import android.os.UserHandle; import java.io.PrintWriter; import java.util.function.Consumer; @@ -76,7 +77,8 @@ class TimeZoneDetectorShellCommand extends ShellCommand { private int runIsAutoDetectionEnabled() { final PrintWriter pw = getOutPrintWriter(); - boolean enabled = mInterface.getCapabilitiesAndConfig() + int userId = UserHandle.USER_CURRENT; + boolean enabled = mInterface.getCapabilitiesAndConfig(userId) .getConfiguration() .isAutoDetectionEnabled(); pw.println(enabled); @@ -92,14 +94,16 @@ class TimeZoneDetectorShellCommand extends ShellCommand { private int runIsLocationEnabled() { final PrintWriter pw = getOutPrintWriter(); - boolean enabled = mInterface.isLocationEnabled(); + int userId = UserHandle.USER_CURRENT; + boolean enabled = mInterface.isLocationEnabled(userId); pw.println(enabled); return 0; } private int runIsGeoDetectionEnabled() { final PrintWriter pw = getOutPrintWriter(); - boolean enabled = mInterface.getCapabilitiesAndConfig() + int userId = UserHandle.USER_CURRENT; + boolean enabled = mInterface.getCapabilitiesAndConfig(userId) .getConfiguration() .isGeoDetectionEnabled(); pw.println(enabled); @@ -108,18 +112,20 @@ class TimeZoneDetectorShellCommand extends ShellCommand { private int runSetAutoDetectionEnabled() { boolean enabled = Boolean.parseBoolean(getNextArgRequired()); + int userId = UserHandle.USER_CURRENT; TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(enabled) .build(); - return mInterface.updateConfiguration(configuration) ? 0 : 1; + return mInterface.updateConfiguration(userId, configuration) ? 0 : 1; } private int runSetGeoDetectionEnabled() { boolean enabled = Boolean.parseBoolean(getNextArgRequired()); + int userId = UserHandle.USER_CURRENT; TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() .setGeoDetectionEnabled(enabled) .build(); - return mInterface.updateConfiguration(configuration) ? 0 : 1; + return mInterface.updateConfiguration(userId, configuration) ? 0 : 1; } private int runSuggestGeolocationTimeZone() { diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index b0847879f456..03cf021d0e9b 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -174,6 +174,10 @@ class ActivityMetricsLogger { boolean allDrawn() { return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn(); } + + boolean contains(ActivityRecord r) { + return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.contains(r); + } } /** The information created when an activity is confirmed to be launched. */ @@ -793,6 +797,7 @@ class ActivityMetricsLogger { stopLaunchTrace(info); if (abort) { + mSupervisor.stopWaitingForActivityVisible(info.mLastLaunchedActivity); launchObserverNotifyActivityLaunchCancelled(info); } else { if (info.isInterestingToLoggerAndObserver()) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 324e3acf8e73..a9c54741fcf6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5435,7 +5435,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final TransitionInfoSnapshot info = mTaskSupervisor .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); if (info != null) { - mTaskSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, + mTaskSupervisor.reportActivityLaunched(false /* timeout */, this, info.windowsFullyDrawnDelayMs, info.getLaunchState()); } } @@ -5476,9 +5476,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // so there is no valid info. But if it is the current top activity (e.g. sleeping), the // invalid state is still reported to make sure the waiting result is notified. if (validInfo || this == getDisplayArea().topRunningActivity()) { - mTaskSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, + mTaskSupervisor.reportActivityLaunched(false /* timeout */, this, windowsDrawnDelayMs, launchState); - mTaskSupervisor.stopWaitingForActivityVisible(this, windowsDrawnDelayMs, launchState); } finishLaunchTickingLocked(); if (task != null) { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 375c3e138a39..c6cc83b4c3bb 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -710,8 +710,12 @@ class ActivityStarter { // WaitResult. mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res, mLastStartActivityRecord, originalOptions); - return getExternalResult(mRequest.waitResult == null ? res - : waitForResult(res, mLastStartActivityRecord)); + if (mRequest.waitResult != null) { + mRequest.waitResult.result = res; + res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord, + launchingState); + } + return getExternalResult(res); } } finally { onExecutionComplete(); @@ -796,48 +800,21 @@ class ActivityStarter { /** * Wait for activity launch completes. */ - private int waitForResult(int res, ActivityRecord r) { - mRequest.waitResult.result = res; - switch(res) { - case START_SUCCESS: { - mSupervisor.mWaitingActivityLaunched.add(mRequest.waitResult); - do { - try { - mService.mGlobalLock.wait(); - } catch (InterruptedException e) { - } - } while (mRequest.waitResult.result != START_TASK_TO_FRONT - && !mRequest.waitResult.timeout && mRequest.waitResult.who == null); - if (mRequest.waitResult.result == START_TASK_TO_FRONT) { - res = START_TASK_TO_FRONT; - } - break; - } - case START_DELIVERED_TO_TOP: { - mRequest.waitResult.timeout = false; - mRequest.waitResult.who = r.mActivityComponent; - mRequest.waitResult.totalTime = 0; - break; - } - case START_TASK_TO_FRONT: { - // ActivityRecord may represent a different activity, but it should not be - // in the resumed state. - if (r.nowVisible && r.isState(RESUMED)) { - mRequest.waitResult.timeout = false; - mRequest.waitResult.who = r.mActivityComponent; - mRequest.waitResult.totalTime = 0; - } else { - mSupervisor.waitActivityVisible(r.mActivityComponent, mRequest.waitResult); - // Note: the timeout variable is not currently not ever set. - do { - try { - mService.mGlobalLock.wait(); - } catch (InterruptedException e) { - } - } while (!mRequest.waitResult.timeout && mRequest.waitResult.who == null); - } - break; - } + private int waitResultIfNeeded(WaitResult waitResult, ActivityRecord r, + LaunchingState launchingState) { + final int res = waitResult.result; + if (res == START_DELIVERED_TO_TOP + || (res == START_TASK_TO_FRONT && r.nowVisible && r.isState(RESUMED))) { + // The activity should already be visible, so nothing to wait. + waitResult.timeout = false; + waitResult.who = r.mActivityComponent; + waitResult.totalTime = 0; + return res; + } + mSupervisor.waitActivityVisibleOrLaunched(waitResult, r, launchingState); + if (res == START_SUCCESS && waitResult.result == START_TASK_TO_FRONT) { + // A trampoline activity is launched and it brings another existing activity to front. + return START_TASK_TO_FRONT; } return res; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 73a6efdb6799..599bf3748dd9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -266,11 +266,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { */ private final SparseIntArray mCurTaskIdForUser = new SparseIntArray(20); - /** List of processes waiting to find out when a specific activity becomes visible. */ - private final ArrayList<WaitInfo> mWaitingForActivityVisible = new ArrayList<>(); - - /** List of processes waiting to find out about the next launched activity. */ - final ArrayList<WaitResult> mWaitingActivityLaunched = new ArrayList<>(); + /** List of requests waiting for the target activity to be launched or visible. */ + private final ArrayList<WaitInfo> mWaitingActivityLaunched = new ArrayList<>(); /** List of activities that are ready to be stopped, but waiting for the next activity to * settle down before doing so. */ @@ -552,9 +549,21 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { return candidateTaskId; } - void waitActivityVisible(ComponentName name, WaitResult result) { - final WaitInfo waitInfo = new WaitInfo(name, result); - mWaitingForActivityVisible.add(waitInfo); + void waitActivityVisibleOrLaunched(WaitResult w, ActivityRecord r, + LaunchingState launchingState) { + if (w.result != ActivityManager.START_TASK_TO_FRONT + && w.result != ActivityManager.START_SUCCESS) { + // Not a result code that can make activity visible or launched. + return; + } + final WaitInfo waitInfo = new WaitInfo(w, r.mActivityComponent, launchingState); + mWaitingActivityLaunched.add(waitInfo); + do { + try { + mService.mGlobalLock.wait(); + } catch (InterruptedException ignored) { + } + } while (mWaitingActivityLaunched.contains(waitInfo)); } void cleanupActivity(ActivityRecord r) { @@ -568,23 +577,25 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { /** There is no valid launch time, just stop waiting. */ void stopWaitingForActivityVisible(ActivityRecord r) { - stopWaitingForActivityVisible(r, WaitResult.INVALID_DELAY, WaitResult.LAUNCH_STATE_UNKNOWN); + reportActivityLaunched(false /* timeout */, r, WaitResult.INVALID_DELAY, + WaitResult.LAUNCH_STATE_UNKNOWN); } - void stopWaitingForActivityVisible(ActivityRecord r, long totalTime, + void reportActivityLaunched(boolean timeout, ActivityRecord r, long totalTime, @WaitResult.LaunchState int launchState) { boolean changed = false; - for (int i = mWaitingForActivityVisible.size() - 1; i >= 0; --i) { - final WaitInfo w = mWaitingForActivityVisible.get(i); - if (w.matches(r.mActivityComponent)) { - final WaitResult result = w.getResult(); - changed = true; - result.timeout = false; - result.who = w.getComponent(); - result.totalTime = totalTime; - result.launchState = launchState; - mWaitingForActivityVisible.remove(w); + for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { + final WaitInfo info = mWaitingActivityLaunched.get(i); + if (!info.matches(r)) { + continue; } + final WaitResult w = info.mResult; + w.timeout = timeout; + w.who = r.mActivityComponent; + w.totalTime = totalTime; + w.launchState = launchState; + mWaitingActivityLaunched.remove(i); + changed = true; } if (changed) { mService.mGlobalLock.notifyAll(); @@ -603,38 +614,18 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { boolean changed = false; for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { - WaitResult w = mWaitingActivityLaunched.remove(i); - if (w.who == null) { - changed = true; - w.result = result; - + final WaitInfo info = mWaitingActivityLaunched.get(i); + if (!info.matches(r)) { + continue; + } + final WaitResult w = info.mResult; + w.result = result; + if (result == START_DELIVERED_TO_TOP) { // Unlike START_TASK_TO_FRONT, When an intent is delivered to top, there // will be no followup launch signals. Assign the result and launched component. - if (result == START_DELIVERED_TO_TOP) { - w.who = r.mActivityComponent; - } - } - } - - if (changed) { - mService.mGlobalLock.notifyAll(); - } - } - - void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, long totalTime, - @WaitResult.LaunchState int launchState) { - boolean changed = false; - for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { - WaitResult w = mWaitingActivityLaunched.remove(i); - if (w.who == null) { + w.who = r.mActivityComponent; + mWaitingActivityLaunched.remove(i); changed = true; - w.timeout = timeout; - if (r != null) { - w.who = new ComponentName(r.info.packageName, r.info.name); - } - w.totalTime = totalTime; - w.launchState = launchState; - // Do not modify w.result. } } if (changed) { @@ -1295,8 +1286,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); r.finishLaunchTickingLocked(); if (fromTimeout) { - reportActivityLaunchedLocked(fromTimeout, r, INVALID_DELAY, - -1 /* launchState */); + reportActivityLaunched(fromTimeout, r, INVALID_DELAY, -1 /* launchState */); } // This is a hack to semi-deal with a race condition @@ -1940,14 +1930,14 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser); pw.println(prefix + "mUserRootTaskInFront=" + mRootWindowContainer.mUserRootTaskInFront); pw.println(prefix + "mVisibilityTransactionDepth=" + mVisibilityTransactionDepth); - if (!mWaitingForActivityVisible.isEmpty()) { - pw.println(prefix + "mWaitingForActivityVisible="); - for (int i = 0; i < mWaitingForActivityVisible.size(); ++i) { - pw.print(prefix + prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix); - } - } pw.print(prefix); pw.print("isHomeRecentsComponent="); pw.println(mRecentTasks.isRecentsComponentHomeActivity(mRootWindowContainer.mCurrentUser)); + if (!mWaitingActivityLaunched.isEmpty()) { + pw.println(prefix + "mWaitingActivityLaunched="); + for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { + mWaitingActivityLaunched.get(i).dump(pw, prefix + " "); + } + } pw.println(); } @@ -2604,32 +2594,30 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { /** * Internal container to store a match qualifier alongside a WaitResult. */ - static class WaitInfo { - private final ComponentName mTargetComponent; - private final WaitResult mResult; - - WaitInfo(ComponentName targetComponent, WaitResult result) { - this.mTargetComponent = targetComponent; - this.mResult = result; - } - - public boolean matches(ComponentName targetComponent) { - return mTargetComponent == null || mTargetComponent.equals(targetComponent); - } + private static class WaitInfo { + final WaitResult mResult; + final ComponentName mTargetComponent; + /** + * The target component may not be the final drawn activity. The launching state is managed + * by {@link ActivityMetricsLogger} that can track consecutive launching sequence. + */ + final LaunchingState mLaunchingState; - public WaitResult getResult() { - return mResult; + WaitInfo(WaitResult result, ComponentName component, LaunchingState launchingState) { + mResult = result; + mTargetComponent = component; + mLaunchingState = launchingState; } - public ComponentName getComponent() { - return mTargetComponent; + boolean matches(ActivityRecord r) { + return mTargetComponent.equals(r.mActivityComponent) || mLaunchingState.contains(r); } - public void dump(PrintWriter pw, String prefix) { + void dump(PrintWriter pw, String prefix) { pw.println(prefix + "WaitInfo:"); pw.println(prefix + " mTargetComponent=" + mTargetComponent); pw.println(prefix + " mResult="); - mResult.dump(pw, prefix); + mResult.dump(pw, prefix + " "); } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 61410f82835e..a88e4537d1a2 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5438,14 +5438,6 @@ class Task extends WindowContainer<WindowContainer> { r.completeResumeLocked(); } - private void clearLaunchTime(ActivityRecord r) { - // Make sure that there is no activity waiting for this to launch. - if (!mTaskSupervisor.mWaitingActivityLaunched.isEmpty()) { - mTaskSupervisor.removeIdleTimeoutForActivity(r); - mTaskSupervisor.scheduleIdleTimeout(r); - } - } - void awakeFromSleepingLocked() { if (!isLeafTask()) { forAllLeafTasks((task) -> task.awakeFromSleepingLocked(), @@ -5588,7 +5580,6 @@ class Task extends WindowContainer<WindowContainer> { mLastNoHistoryActivity = prev.isNoHistory() ? prev : null; prev.setState(PAUSING, "startPausingLocked"); prev.getTask().touchActiveTime(); - clearLaunchTime(prev); mAtmService.updateCpuStats(); diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd index 992470816068..a62e2c385766 100644 --- a/services/core/xsd/platform-compat-config.xsd +++ b/services/core/xsd/platform-compat-config.xsd @@ -31,6 +31,7 @@ <xs:attribute type="xs:int" name="enableAfterTargetSdk"/> <xs:attribute type="xs:int" name="enableSinceTargetSdk"/> <xs:attribute type="xs:string" name="description"/> + <xs:attribute type="xs:boolean" name="overridable"/> </xs:extension> </xs:simpleContent> </xs:complexType> @@ -48,7 +49,3 @@ </xs:unique> </xs:element> </xs:schema> - - - - diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt index e3640edd0201..fb8bbefd8374 100644 --- a/services/core/xsd/platform-compat-schema/current.txt +++ b/services/core/xsd/platform-compat-schema/current.txt @@ -10,6 +10,7 @@ package com.android.server.compat.config { method public long getId(); method public boolean getLoggingOnly(); method public String getName(); + method public boolean getOverridable(); method public String getValue(); method public void setDescription(String); method public void setDisabled(boolean); @@ -18,6 +19,7 @@ package com.android.server.compat.config { method public void setId(long); method public void setLoggingOnly(boolean); method public void setName(String); + method public void setOverridable(boolean); method public void setValue(String); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java index a281180d77d1..48f8b1505d3a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java @@ -134,6 +134,8 @@ class ActiveAdmin { private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown"; private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode"; private static final String TAG_PASSWORD_COMPLEXITY = "password-complexity"; + private static final String TAG_ORGANIZATION_ID = "organization-id"; + private static final String TAG_ENROLLMENT_SPECIFIC_ID = "enrollment-specific-id"; private static final String ATTR_VALUE = "value"; private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification"; private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; @@ -273,6 +275,8 @@ class ActiveAdmin { public String mAlwaysOnVpnPackage; public boolean mAlwaysOnVpnLockdown; boolean mCommonCriteriaMode; + public String mOrganizationId; + public String mEnrollmentSpecificId; ActiveAdmin(DeviceAdminInfo info, boolean isParent) { this.info = info; @@ -533,6 +537,12 @@ class ActiveAdmin { if (mPasswordComplexity != PASSWORD_COMPLEXITY_NONE) { writeAttributeValueToXml(out, TAG_PASSWORD_COMPLEXITY, mPasswordComplexity); } + if (!TextUtils.isEmpty(mOrganizationId)) { + writeTextToXml(out, TAG_ORGANIZATION_ID, mOrganizationId); + } + if (!TextUtils.isEmpty(mEnrollmentSpecificId)) { + writeTextToXml(out, TAG_ENROLLMENT_SPECIFIC_ID, mEnrollmentSpecificId); + } } void writeTextToXml(TypedXmlSerializer out, String tag, String text) throws IOException { @@ -766,6 +776,22 @@ class ActiveAdmin { mCommonCriteriaMode = parser.getAttributeBoolean(null, ATTR_VALUE, false); } else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) { mPasswordComplexity = parser.getAttributeInt(null, ATTR_VALUE); + } else if (TAG_ORGANIZATION_ID.equals(tag)) { + type = parser.next(); + if (type == TypedXmlPullParser.TEXT) { + mOrganizationId = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing Organization ID."); + } + } else if (TAG_ENROLLMENT_SPECIFIC_ID.equals(tag)) { + type = parser.next(); + if (type == TypedXmlPullParser.TEXT) { + mEnrollmentSpecificId = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing Enrollment-specific ID."); + } } else { Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -1107,5 +1133,15 @@ class ActiveAdmin { pw.print("mPasswordComplexity="); pw.println(mPasswordComplexity); + + if (!TextUtils.isEmpty(mOrganizationId)) { + pw.print("mOrganizationId="); + pw.println(mOrganizationId); + } + + if (!TextUtils.isEmpty(mEnrollmentSpecificId)) { + pw.print("mEnrollmentSpecificId="); + pw.println(mEnrollmentSpecificId); + } } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 6f1d451e7224..22e9725f49ab 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -15,6 +15,7 @@ */ package com.android.server.devicepolicy; +import android.annotation.NonNull; import android.app.admin.DevicePolicySafetyChecker; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; @@ -101,4 +102,11 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public boolean canProfileOwnerResetPasswordWhenLocked(int userId) { return false; } + + public String getEnrollmentSpecificId() { + return ""; + } + + public void setOrganizationIdForUser( + @NonNull String callerPackage, @NonNull String enterpriseId, int userId) {} } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 3e51b7506dff..4654fca250a3 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -819,6 +819,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle); + removeCredentialManagementApp(intent.getData().getSchemeSpecificPart()); } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)) { clearWipeProfileNotification(); } else if (Intent.ACTION_DATE_CHANGED.equals(action) @@ -949,6 +950,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + private void removeCredentialManagementApp(String packageName) { + mBackgroundHandler.post(() -> { + try (KeyChainConnection connection = mInjector.keyChainBind()) { + IKeyChainService service = connection.getService(); + if (service.hasCredentialManagementApp() + && packageName.equals(service.getCredentialManagementAppPackageName())) { + service.removeCredentialManagementApp(); + } + } catch (RemoteException | InterruptedException | IllegalStateException e) { + Log.e(LOG_TAG, "Unable to remove the credential management app"); + } + }); + } + private boolean isRemovedPackage(String changedPackage, String targetPackage, int userHandle) { try { return targetPackage != null @@ -1419,6 +1434,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return SecurityLog.isLoggingEnabled(); } + KeyChainConnection keyChainBind() throws InterruptedException { + return KeyChain.bind(mContext); + } + KeyChainConnection keyChainBindAsUser(UserHandle user) throws InterruptedException { return KeyChain.bindAsUser(mContext, user); } @@ -15581,4 +15600,69 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return true; } } + + @Override + public String getEnrollmentSpecificId() { + if (!mHasFeature) { + return ""; + } + + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization( + isDeviceOwner(caller) || isProfileOwner(caller)); + + synchronized (getLockObject()) { + final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked( + caller.getUserId()); + final String esid = requiredAdmin.mEnrollmentSpecificId; + return esid != null ? esid : ""; + } + } + + @Override + public void setOrganizationIdForUser( + @NonNull String callerPackage, @NonNull String organizationId, int userId) { + if (!mHasFeature) { + return; + } + Objects.requireNonNull(callerPackage); + + final CallerIdentity caller = getCallerIdentity(callerPackage); + // Only the DPC can set this ID. + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller), + "Only a Device Owner or Profile Owner may set the Enterprise ID."); + // Empty enterprise ID must not be provided in calls to this method. + Preconditions.checkArgument(!TextUtils.isEmpty(organizationId), + "Enterprise ID may not be empty."); + + Log.i(LOG_TAG, + String.format("Setting Enterprise ID to %s for user %d", organizationId, userId)); + + synchronized (getLockObject()) { + ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId); + // As the caller is the system, it must specify the component name of the profile owner + // as a safety check. + Preconditions.checkCallAuthorization( + owner != null && owner.getUserHandle().getIdentifier() == userId, + String.format("The Profile Owner or Device Owner may only set the Enterprise ID" + + " on its own user, called on user %d but owner user is %d", userId, + owner.getUserHandle().getIdentifier())); + Preconditions.checkState( + TextUtils.isEmpty(owner.mOrganizationId) || owner.mOrganizationId.equals( + organizationId), + "The organization ID has been previously set to a different value and cannot " + + "be changed"); + final String dpcPackage = owner.info.getPackageName(); + mInjector.binderWithCleanCallingIdentity(() -> { + EnterpriseSpecificIdCalculator esidCalculator = + new EnterpriseSpecificIdCalculator(mContext); + + final String esid = esidCalculator.calculateEnterpriseId(dpcPackage, + organizationId); + owner.mOrganizationId = organizationId; + owner.mEnrollmentSpecificId = esid; + saveSettingsLocked(userId); + }); + } + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java new file mode 100644 index 000000000000..df7f3084aeb3 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java @@ -0,0 +1,145 @@ +/* + * 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.devicepolicy; + +import android.content.Context; +import android.content.pm.VerifierDeviceIdentity; +import android.net.wifi.WifiManager; +import android.os.Build; +import android.security.identity.Util; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; + +import java.nio.ByteBuffer; + +class EnterpriseSpecificIdCalculator { + private static final int PADDED_HW_ID_LENGTH = 16; + private static final int PADDED_PROFILE_OWNER_LENGTH = 64; + private static final int PADDED_ENTERPRISE_ID_LENGTH = 64; + private static final int ESID_LENGTH = 16; + + private final String mImei; + private final String mMeid; + private final String mSerialNumber; + private final String mMacAddress; + + @VisibleForTesting + EnterpriseSpecificIdCalculator(String imei, String meid, String serialNumber, + String macAddress) { + mImei = imei; + mMeid = meid; + mSerialNumber = serialNumber; + mMacAddress = macAddress; + } + + EnterpriseSpecificIdCalculator(Context context) { + TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class); + Preconditions.checkState(telephonyService != null, "Unable to access telephony service"); + mImei = telephonyService.getImei(0); + mMeid = telephonyService.getMeid(0); + mSerialNumber = Build.getSerial(); + WifiManager wifiManager = context.getSystemService(WifiManager.class); + Preconditions.checkState(wifiManager != null, "Unable to access WiFi service"); + final String[] macAddresses = wifiManager.getFactoryMacAddresses(); + if (macAddresses == null || macAddresses.length == 0) { + mMacAddress = ""; + } else { + mMacAddress = macAddresses[0]; + } + } + + private static String getPaddedTruncatedString(String input, int maxLength) { + final String paddedValue = String.format("%" + maxLength + "s", input); + return paddedValue.substring(0, maxLength); + } + + private static String getPaddedHardwareIdentifier(String hardwareIdentifier) { + if (hardwareIdentifier == null) { + hardwareIdentifier = ""; + } + return getPaddedTruncatedString(hardwareIdentifier, PADDED_HW_ID_LENGTH); + } + + String getPaddedImei() { + return getPaddedHardwareIdentifier(mImei); + } + + String getPaddedMeid() { + return getPaddedHardwareIdentifier(mMeid); + } + + String getPaddedSerialNumber() { + return getPaddedHardwareIdentifier(mSerialNumber); + } + + String getPaddedProfileOwnerName(String profileOwnerPackage) { + return getPaddedTruncatedString(profileOwnerPackage, PADDED_PROFILE_OWNER_LENGTH); + } + + String getPaddedEnterpriseId(String enterpriseId) { + return getPaddedTruncatedString(enterpriseId, PADDED_ENTERPRISE_ID_LENGTH); + } + + /** + * Calculates the ESID. + * @param profileOwnerPackage Package of the Device Policy Client that manages the device/ + * profile. May not be null. + * @param enterpriseIdString The identifier for the enterprise in which the device/profile is + * being enrolled. This parameter may not be empty, but may be null. + * If called with {@code null}, will calculate an ESID with empty + * Enterprise ID. + */ + public String calculateEnterpriseId(String profileOwnerPackage, String enterpriseIdString) { + Preconditions.checkArgument(!TextUtils.isEmpty(profileOwnerPackage), + "owner package must be specified."); + + Preconditions.checkArgument(enterpriseIdString == null || !enterpriseIdString.isEmpty(), + "enterprise ID must either be null or non-empty."); + + if (enterpriseIdString == null) { + enterpriseIdString = ""; + } + + final byte[] serialNumber = getPaddedSerialNumber().getBytes(); + final byte[] imei = getPaddedImei().getBytes(); + final byte[] meid = getPaddedMeid().getBytes(); + final byte[] macAddress = mMacAddress.getBytes(); + final int totalIdentifiersLength = serialNumber.length + imei.length + meid.length + + macAddress.length; + final ByteBuffer fixedIdentifiers = ByteBuffer.allocate(totalIdentifiersLength); + fixedIdentifiers.put(serialNumber); + fixedIdentifiers.put(imei); + fixedIdentifiers.put(meid); + fixedIdentifiers.put(macAddress); + + final byte[] dpcPackage = getPaddedProfileOwnerName(profileOwnerPackage).getBytes(); + final byte[] enterpriseId = getPaddedEnterpriseId(enterpriseIdString).getBytes(); + final ByteBuffer info = ByteBuffer.allocate(dpcPackage.length + enterpriseId.length); + info.put(dpcPackage); + info.put(enterpriseId); + final byte[] esidBytes = Util.computeHkdf("HMACSHA256", fixedIdentifiers.array(), null, + info.array(), ESID_LENGTH); + ByteBuffer esidByteBuffer = ByteBuffer.wrap(esidBytes); + + VerifierDeviceIdentity firstId = new VerifierDeviceIdentity(esidByteBuffer.getLong()); + VerifierDeviceIdentity secondId = new VerifierDeviceIdentity(esidByteBuffer.getLong()); + return firstId.toString() + secondId.toString(); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java index 3220dff553d3..a691a8d44e48 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java @@ -313,29 +313,30 @@ public class AppStateTrackerTest { } } - private static final int NONE = 0; - private static final int ALARMS_ONLY = 1 << 0; - private static final int JOBS_ONLY = 1 << 1; - private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY; - - private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName, - int restrictionTypes, boolean exemptFromBatterySaver) { - assertEquals(((restrictionTypes & JOBS_ONLY) != 0), - instance.areJobsRestricted(uid, packageName, exemptFromBatterySaver)); - assertEquals(((restrictionTypes & ALARMS_ONLY) != 0), - instance.areAlarmsRestricted(uid, packageName, exemptFromBatterySaver)); + private void areJobsRestricted(AppStateTrackerTestable instance, int[] uids, String[] packages, + boolean[] restricted, boolean exemption) { + assertTrue(uids.length == packages.length && uids.length == restricted.length); + for (int i = 0; i < uids.length; i++) { + assertEquals(restricted[i], + instance.areJobsRestricted(uids[i], packages[i], exemption)); + } } - private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName, - int restrictionTypes) { - areRestricted(instance, uid, packageName, restrictionTypes, - /*exemptFromBatterySaver=*/ false); + private void areAlarmsRestrictedByFAS(AppStateTrackerTestable instance, int[] uids, + String[] packages, boolean[] restricted) { + assertTrue(uids.length == packages.length && uids.length == restricted.length); + for (int i = 0; i < uids.length; i++) { + assertEquals(restricted[i], instance.areAlarmsRestricted(uids[i], packages[i])); + } } - private void areRestrictedWithExemption(AppStateTrackerTestable instance, - int uid, String packageName, int restrictionTypes) { - areRestricted(instance, uid, packageName, restrictionTypes, - /*exemptFromBatterySaver=*/ true); + private void areAlarmsRestrictedByBatterySaver(AppStateTrackerTestable instance, int[] uids, + String[] packages, boolean[] restricted) { + assertTrue(uids.length == packages.length && uids.length == restricted.length); + for (int i = 0; i < uids.length; i++) { + assertEquals(restricted[i], + instance.areAlarmsRestrictedByBatterySaver(uids[i], packages[i])); + } } @Test @@ -344,30 +345,42 @@ public class AppStateTrackerTest { callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, NONE); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); - areRestrictedWithExemption(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}); mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); assertTrue(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, NONE); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); - areRestrictedWithExemption(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); // Toggle the foreground state. - mPowerSaveMode = true; - mPowerSaveObserver.accept(getPowerSaveState()); assertFalse(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); @@ -376,34 +389,65 @@ public class AppStateTrackerTest { mIUidObserver.onUidActive(UID_1); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}); + assertTrue(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); mIUidObserver.onUidGone(UID_1, /*disable=*/ false); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); + assertFalse(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); mIUidObserver.onUidActive(UID_1); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}); mIUidObserver.onUidIdle(UID_1, /*disable=*/ false); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); + assertFalse(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); @@ -416,11 +460,19 @@ public class AppStateTrackerTest { assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2)); assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2)); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, UID_10_2, PACKAGE_2, NONE); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); setAppOps(UID_1, PACKAGE_1, true); setAppOps(UID_10_2, PACKAGE_2, true); @@ -429,24 +481,72 @@ public class AppStateTrackerTest { assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2)); assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2)); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}); // Toggle power saver, should still be the same. mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}); + mPowerSaveMode = false; mPowerSaveObserver.accept(getPowerSaveState()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}); // Clear the app ops and update the exemption list. setAppOps(UID_1, PACKAGE_1, false); @@ -455,24 +555,41 @@ public class AppStateTrackerTest { mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); instance.setPowerSaveExemptionListAppIds(new int[] {UID_1}, new int[] {}, new int[] {UID_2}); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_10_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, true, true, false}, + false); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, true, true, true, true, false}); // Again, make sure toggling the global state doesn't change it. mPowerSaveMode = false; @@ -481,13 +598,18 @@ public class AppStateTrackerTest { mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_10_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, true, true, false}, + false); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, true, true, true, true, false}); assertTrue(instance.isUidPowerSaveExempt(UID_1)); assertTrue(instance.isUidPowerSaveExempt(UID_10_1)); @@ -646,52 +768,98 @@ public class AppStateTrackerTest { } @Test - public void testExempt() throws Exception { + public void testExemptedBucket() throws Exception { final AppStateTrackerTestable instance = newInstance(); callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false}); mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); assertTrue(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); // Exempt package 2 on user-10. mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 10, false, UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, NONE); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); - areRestrictedWithExemption(instance, UID_10_2, PACKAGE_2, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, true, false}); // Exempt package 1 on user-0. mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_1, /*user=*/ 0, false, UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, false}); // Unexempt package 2 on user-10. mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 10, false, UsageStatsManager.STANDBY_BUCKET_ACTIVE, REASON_MAIN_USAGE); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, true}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, true}); // Check force-app-standby. // EXEMPT doesn't exempt from force-app-standby. @@ -703,13 +871,28 @@ public class AppStateTrackerTest { mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 0, false, UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); + // All 3 packages (u0:p1, u0:p2, u10:p2) are now in the exempted bucket. setAppOps(UID_1, PACKAGE_1, true); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, false, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, false, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, false, false}); } @Test @@ -809,6 +992,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -823,7 +1008,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -853,6 +1040,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -865,6 +1054,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(1)).unblockAlarmsForUidPackage(eq(UID_10_2), eq(PACKAGE_2)); @@ -876,15 +1067,16 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); - // Unrestrict while battery saver is on. Shouldn't fire. + // Test overlap with battery saver mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); - // Note toggling appops while BS is on will suppress unblockAlarmsForUidPackage(). setAppOps(UID_10_2, PACKAGE_2, true); waitUntilMainHandlerDrain(); @@ -892,6 +1084,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean()); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -906,7 +1100,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -922,7 +1118,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(0)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(1)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -934,7 +1132,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -948,6 +1148,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -961,12 +1163,14 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); - // Do the same thing with battery saver on. (Currently same callbacks are called.) + // Do the same thing with battery saver on. mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); @@ -975,6 +1179,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -989,7 +1195,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(0)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(1)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -1001,7 +1209,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -1015,6 +1225,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1028,6 +1240,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1037,9 +1251,8 @@ public class AppStateTrackerTest { // ------------------------------------------------------------------------- // Tests with proc state changes. - // With battery save. - mPowerSaveMode = true; - mPowerSaveObserver.accept(getPowerSaveState()); + // With battery saver. + // Battery saver is already on. mIUidObserver.onUidActive(UID_10_1); @@ -1049,6 +1262,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1062,6 +1277,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1075,6 +1292,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1088,12 +1307,14 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); - // Without battery save. + // Without battery saver. mPowerSaveMode = false; mPowerSaveObserver.accept(getPowerSaveState()); @@ -1102,7 +1323,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1)); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -1115,6 +1338,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1128,6 +1353,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1141,6 +1368,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1154,6 +1383,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java index f375421043fd..fd364ae77240 100644 --- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java @@ -233,8 +233,10 @@ public class RescuePartyTest { verifiedTimesMap); noteBoot(4); + assertTrue(RescueParty.isRebootPropertySet()); - assertTrue(RescueParty.isAttemptingFactoryReset()); + noteBoot(5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -255,7 +257,10 @@ public class RescuePartyTest { /*configResetVerifiedTimesMap=*/ null); notePersistentAppCrash(4); - assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isRebootPropertySet()); + + notePersistentAppCrash(5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -306,7 +311,11 @@ public class RescuePartyTest { observer.execute(new VersionedPackage( CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4); - assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isRebootPropertySet()); + + observer.execute(new VersionedPackage( + CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -367,7 +376,11 @@ public class RescuePartyTest { observer.execute(new VersionedPackage( CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4); - assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isRebootPropertySet()); + + observer.execute(new VersionedPackage( + CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -376,6 +389,7 @@ public class RescuePartyTest { noteBoot(i + 1); } assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -424,7 +438,7 @@ public class RescuePartyTest { for (int i = 0; i < LEVEL_FACTORY_RESET; i++) { noteBoot(i + 1); } - assertFalse(RescueParty.isAttemptingFactoryReset()); + assertFalse(RescueParty.isFactoryResetPropertySet()); // Restore the property value initialized in SetUp() SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, ""); diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 8edac4f8ce58..7a970a1c3d46 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -52,6 +52,7 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENE import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_FUTURITY; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_INTERVAL; +import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY; import static com.android.server.alarm.AlarmManagerService.IS_WAKEUP_MASK; import static com.android.server.alarm.AlarmManagerService.TIME_CHANGED_MASK; import static com.android.server.alarm.AlarmManagerService.WORKING_INDEX; @@ -71,6 +72,7 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -817,14 +819,14 @@ public class AlarmManagerServiceTest { } @Test - public void testAlarmRestrictedInBatterySaver() throws Exception { + public void testAlarmRestrictedByFAS() throws Exception { final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); final PendingIntent alarmPi = getNewMockPendingIntent(); - when(mAppStateTracker.areAlarmsRestricted(TEST_CALLING_UID, TEST_CALLING_PACKAGE, - false)).thenReturn(true); + when(mAppStateTracker.areAlarmsRestricted(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, alarmPi); assertEquals(mNowElapsedTest + 2, mTestTimer.getElapsed()); @@ -1301,7 +1303,6 @@ public class AlarmManagerServiceTest { final long awiDelayForTest = 23; setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, awiDelayForTest); - setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, 0); setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1000, getNewMockPendingIntent()); @@ -1336,7 +1337,7 @@ public class AlarmManagerServiceTest { } @Test - public void allowWhileIdleUnrestricted() throws Exception { + public void allowWhileIdleUnrestrictedInIdle() throws Exception { doReturn(0).when(mService).fuzzForDuration(anyLong()); final long awiDelayForTest = 127; @@ -1361,7 +1362,7 @@ public class AlarmManagerServiceTest { } @Test - public void deviceIdleThrottling() throws Exception { + public void deviceIdleDeferralOnSet() throws Exception { doReturn(0).when(mService).fuzzForDuration(anyLong()); final long deviceIdleUntil = mNowElapsedTest + 1234; @@ -1386,6 +1387,123 @@ public class AlarmManagerServiceTest { } @Test + public void deviceIdleStateChanges() throws Exception { + doReturn(0).when(mService).fuzzForDuration(anyLong()); + + final int numAlarms = 10; + final PendingIntent[] pis = new PendingIntent[numAlarms]; + for (int i = 0; i < numAlarms; i++) { + setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + i + 1, + pis[i] = getNewMockPendingIntent()); + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + } + + final PendingIntent idleUntil = getNewMockPendingIntent(); + setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1234, idleUntil); + + assertEquals(mNowElapsedTest + 1234, mTestTimer.getElapsed()); + + mNowElapsedTest += 5; + mTestTimer.expire(); + // Nothing should happen. + verify(pis[0], never()).send(eq(mMockContext), eq(0), any(Intent.class), any(), + any(Handler.class), isNull(), any()); + + mService.removeLocked(idleUntil, null); + mTestTimer.expire(); + // Now, the first 5 alarms (upto i = 4) should expire. + for (int i = 0; i < 5; i++) { + verify(pis[i]).send(eq(mMockContext), eq(0), any(Intent.class), any(), + any(Handler.class), isNull(), any()); + } + // Rest should be restored, so the timer should reflect the next alarm. + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + } + + @Test + public void batterySaverThrottling() { + final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = + ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); + verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); + final AppStateTrackerImpl.Listener listener = listenerArgumentCaptor.getValue(); + + final PendingIntent alarmPi = getNewMockPendingIntent(); + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); + setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 7, alarmPi); + assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed()); + + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(false); + listener.updateAllAlarms(); + assertEquals(mNowElapsedTest + 7, mTestTimer.getElapsed()); + + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); + listener.updateAlarmsForUid(TEST_CALLING_UID); + assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed()); + } + + @Test + public void allowWhileIdleAlarmsInBatterySaver() throws Exception { + final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = + ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); + verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); + final AppStateTrackerImpl.Listener listener = listenerArgumentCaptor.getValue(); + + final long longDelay = 23; + final long shortDelay = 7; + setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, longDelay); + setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, shortDelay); + + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1, + getNewMockPendingIntent(), false); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, + getNewMockPendingIntent(), false); + + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + + mNowElapsedTest += 1; + mTestTimer.expire(); + + assertEquals(mNowElapsedTest + longDelay, mTestTimer.getElapsed()); + listener.onUidForeground(TEST_CALLING_UID, true); + // The next alarm should be deferred by shortDelay. + assertEquals(mNowElapsedTest + shortDelay, mTestTimer.getElapsed()); + + mNowElapsedTest = mTestTimer.getElapsed(); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1, + getNewMockPendingIntent(), false); + + when(mAppStateTracker.isUidInForeground(TEST_CALLING_UID)).thenReturn(true); + mTestTimer.expire(); + // The next alarm should be deferred by shortDelay again. + assertEquals(mNowElapsedTest + shortDelay, mTestTimer.getElapsed()); + + mNowElapsedTest = mTestTimer.getElapsed(); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1, + getNewMockPendingIntent(), true); + when(mAppStateTracker.isUidInForeground(TEST_CALLING_UID)).thenReturn(false); + mTestTimer.expire(); + final long lastAwiDispatch = mNowElapsedTest; + // Unrestricted, so should not be changed. + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + + mNowElapsedTest = mTestTimer.getElapsed(); + // AWI_unrestricted should not affect normal AWI bookkeeping. + // The next alarm is after the short delay but before the long delay. + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, lastAwiDispatch + shortDelay + 1, + getNewMockPendingIntent(), false); + mTestTimer.expire(); + assertEquals(lastAwiDispatch + longDelay, mTestTimer.getElapsed()); + + listener.onUidForeground(TEST_CALLING_UID, true); + assertEquals(lastAwiDispatch + shortDelay + 1, mTestTimer.getElapsed()); + } + + @Test public void dispatchOrder() throws Exception { doReturn(0).when(mService).fuzzForDuration(anyLong()); diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java index 4f4aa3f16f09..f00edcc85404 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -40,78 +40,83 @@ class CompatConfigBuilder { } CompatConfigBuilder addEnableAfterSdkChangeWithId(int sdk, long id) { - mChanges.add(new CompatChange(id, "", sdk, -1, false, false, "")); + mChanges.add(new CompatChange(id, "", sdk, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnableAfterSdkChangeWithIdAndName(int sdk, long id, String name) { - mChanges.add(new CompatChange(id, name, sdk, -1, false, false, "")); + mChanges.add(new CompatChange(id, name, sdk, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnableAfterSdkChangeWithIdDefaultDisabled(int sdk, long id) { - mChanges.add(new CompatChange(id, "", sdk, -1, true, false, "")); + mChanges.add(new CompatChange(id, "", sdk, -1, true, false, "", false)); return this; } CompatConfigBuilder addEnableAfterSdkChangeWithIdAndDescription(int sdk, long id, String description) { - mChanges.add(new CompatChange(id, "", sdk, -1, false, false, description)); + mChanges.add(new CompatChange(id, "", sdk, -1, false, false, description, false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithId(int sdk, long id) { - mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "")); + mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "", false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithIdAndName(int sdk, long id, String name) { - mChanges.add(new CompatChange(id, name, -1, sdk, false, false, "")); + mChanges.add(new CompatChange(id, name, -1, sdk, false, false, "", false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithIdDefaultDisabled(int sdk, long id) { - mChanges.add(new CompatChange(id, "", -1, sdk, true, false, "")); + mChanges.add(new CompatChange(id, "", -1, sdk, true, false, "", false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithIdAndDescription(int sdk, long id, String description) { - mChanges.add(new CompatChange(id, "", -1, sdk, false, false, description)); + mChanges.add(new CompatChange(id, "", -1, sdk, false, false, description, false)); return this; } CompatConfigBuilder addEnabledChangeWithId(long id) { - mChanges.add(new CompatChange(id, "", -1, -1, false, false, "")); + mChanges.add(new CompatChange(id, "", -1, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) { - mChanges.add(new CompatChange(id, name, -1, -1, false, false, "")); + mChanges.add(new CompatChange(id, name, -1, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) { - mChanges.add(new CompatChange(id, "", -1, -1, false, false, description)); + mChanges.add(new CompatChange(id, "", -1, -1, false, false, description, false)); return this; } CompatConfigBuilder addDisabledChangeWithId(long id) { - mChanges.add(new CompatChange(id, "", -1, -1, true, false, "")); + mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", false)); return this; } CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) { - mChanges.add(new CompatChange(id, name, -1, -1, true, false, "")); + mChanges.add(new CompatChange(id, name, -1, -1, true, false, "", false)); return this; } CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) { - mChanges.add(new CompatChange(id, "", -1, -1, true, false, description)); + mChanges.add(new CompatChange(id, "", -1, -1, true, false, description, false)); return this; } CompatConfigBuilder addLoggingOnlyChangeWithId(long id) { - mChanges.add(new CompatChange(id, "", -1, -1, false, true, "")); + mChanges.add(new CompatChange(id, "", -1, -1, false, true, "", false)); + return this; + } + + CompatConfigBuilder addOverridableChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, -1, false, true, "", true)); return this; } diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index a70c51045340..a1b2dc8bd82d 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -97,17 +97,22 @@ public class PlatformCompatTest { .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.Q, 5L) .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.R, 6L) .addLoggingOnlyChangeWithId(7L) + .addOverridableChangeWithId(8L) .build(); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly( - new CompatibilityChangeInfo(1L, "", -1, -1, false, false, ""), - new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, ""), + new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), + new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), new CompatibilityChangeInfo(3L, "", Build.VERSION_CODES.O, -1, false, false, - "desc"), - new CompatibilityChangeInfo(4L, "", Build.VERSION_CODES.P, -1, false, false, ""), - new CompatibilityChangeInfo(5L, "", Build.VERSION_CODES.Q, -1, false, false, ""), - new CompatibilityChangeInfo(6L, "", Build.VERSION_CODES.R, -1, false, false, ""), - new CompatibilityChangeInfo(7L, "", -1, -1, false, true, "")); + "desc", false), + new CompatibilityChangeInfo( + 4L, "", Build.VERSION_CODES.P, -1, false, false, "", false), + new CompatibilityChangeInfo( + 5L, "", Build.VERSION_CODES.Q, -1, false, false, "", false), + new CompatibilityChangeInfo( + 6L, "", Build.VERSION_CODES.R, -1, false, false, "", false), + new CompatibilityChangeInfo(7L, "", -1, -1, false, true, "", false), + new CompatibilityChangeInfo(8L, "", -1, -1, false, true, "", true)); } @Test @@ -123,12 +128,12 @@ public class PlatformCompatTest { .build(); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly( - new CompatibilityChangeInfo(1L, "", -1, -1, false, false, ""), - new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, ""), - new CompatibilityChangeInfo(5L, "", /*enableAfter*/ -1, - /*enableSince*/ Build.VERSION_CODES.Q, false, false, ""), - new CompatibilityChangeInfo(6L, "", /*enableAfter*/ -1, - /*enableSince*/ Build.VERSION_CODES.R, false, false, "")); + new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), + new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), + new CompatibilityChangeInfo( + 5L, "", Build.VERSION_CODES.P, -1, false, false, "", false), + new CompatibilityChangeInfo( + 6L, "", Build.VERSION_CODES.Q, -1, false, false, "", false)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 17324bab70d2..9c28c99fcc07 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -460,6 +460,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override + KeyChain.KeyChainConnection keyChainBind() { + return services.keyChainConnection; + } + + @Override KeyChain.KeyChainConnection keyChainBindAsUser(UserHandle user) { return services.keyChainConnection; } 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 c1b1133dbb22..39fa20e4153f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1628,6 +1628,33 @@ public class DevicePolicyManagerTest extends DpmTestBase { )), eq(user)); } + @Test + public void testRemoveCredentialManagementApp() throws Exception { + final String packageName = "com.test.cred.mng"; + Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); + intent.setData(Uri.parse("package:" + packageName)); + dpms.mReceiver.setPendingResult( + new BroadcastReceiver.PendingResult(Activity.RESULT_OK, + "resultData", + /* resultExtras= */ null, + BroadcastReceiver.PendingResult.TYPE_UNREGISTERED, + /* ordered= */ true, + /* sticky= */ false, + /* token= */ null, + CALLER_USER_HANDLE, + /* flags= */ 0)); + when(getServices().keyChainConnection.getService().hasCredentialManagementApp()) + .thenReturn(true); + when(getServices().keyChainConnection.getService().getCredentialManagementAppPackageName()) + .thenReturn(packageName); + + dpms.mReceiver.onReceive(mContext, intent); + + flushTasks(dpms); + verify(getServices().keyChainConnection.getService()).hasCredentialManagementApp(); + verify(getServices().keyChainConnection.getService()).removeCredentialManagementApp(); + } + /** * Simple test for delegate set/get and general delegation. Tests verifying that delegated * privileges can acually be exercised by a delegate are not covered here. diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java new file mode 100644 index 000000000000..c2c1d5b4f3be --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java @@ -0,0 +1,107 @@ +/* + * 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.devicepolicy; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.assertThrows; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class EnterpriseSpecificIdCalculatorTest { + private static final String SOME_IMEI = "56134231542345"; + private static final String SOME_SERIAL_NUMBER = "XZ663CCAJA7"; + private static final String SOME_MAC_ADDRESS = "65:ca:f3:fe:9d:b1"; + private static final String NO_MEID = null; + private static final String SOME_PACKAGE = "com.example.test.dpc"; + private static final String ANOTHER_PACKAGE = "org.example.test.another.dpc"; + private static final String SOME_ENTERPRISE_ID = "73456234"; + private static final String ANOTHER_ENTERPRISE_ID = "243441"; + + private EnterpriseSpecificIdCalculator mEsidCalculator; + + @Before + public void createDefaultEsidCalculator() { + mEsidCalculator = new EnterpriseSpecificIdCalculator(SOME_IMEI, NO_MEID, SOME_SERIAL_NUMBER, + SOME_MAC_ADDRESS); + } + + @Test + public void paddingOfIdentifiers() { + assertThat(mEsidCalculator.getPaddedImei()).isEqualTo(" 56134231542345"); + assertThat(mEsidCalculator.getPaddedMeid()).isEqualTo(" "); + assertThat(mEsidCalculator.getPaddedSerialNumber()).isEqualTo(" XZ663CCAJA7"); + } + + @Test + public void truncationOfLongIdentifier() { + EnterpriseSpecificIdCalculator esidCalculator = new EnterpriseSpecificIdCalculator( + SOME_IMEI, NO_MEID, "XZ663CCAJA7XZ663CCAJA7XZ663CCAJA7", + SOME_MAC_ADDRESS); + assertThat(esidCalculator.getPaddedSerialNumber()).isEqualTo("XZ663CCAJA7XZ663"); + } + + @Test + public void paddingOfPackageName() { + assertThat(mEsidCalculator.getPaddedProfileOwnerName(SOME_PACKAGE)).isEqualTo( + " " + SOME_PACKAGE); + } + + @Test + public void paddingOfEnterpriseId() { + assertThat(mEsidCalculator.getPaddedEnterpriseId(SOME_ENTERPRISE_ID)).isEqualTo( + " " + SOME_ENTERPRISE_ID); + } + + @Test + public void emptyEnterpriseIdYieldsEmptyEsid() { + assertThrows(IllegalArgumentException.class, () -> + mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, "")); + } + + @Test + public void emptyDpcPackageYieldsEmptyEsid() { + assertThrows(IllegalArgumentException.class, () -> + mEsidCalculator.calculateEnterpriseId("", SOME_ENTERPRISE_ID)); + } + + // On upgrade, an ESID will be calculated with an empty Enterprise ID. This is signalled + // to the EnterpriseSpecificIdCalculator by passing in null. + @Test + public void nullEnterpriseIdYieldsValidEsid() { + assertThat(mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, null)).isEqualTo( + "C4W7-VUJT-PHSA-HMY53-CLHX-L4HW-L"); + } + + @Test + public void knownValues() { + assertThat( + mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, SOME_ENTERPRISE_ID)).isEqualTo( + "FP7B-RXQW-Q77F-7J6FC-5RXZ-UJI6-6"); + assertThat(mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, + ANOTHER_ENTERPRISE_ID)).isEqualTo("ATAL-VPIX-GBNZ-NE3TF-TDEV-3OVO-C"); + assertThat(mEsidCalculator.calculateEnterpriseId(ANOTHER_PACKAGE, + SOME_ENTERPRISE_ID)).isEqualTo("JHU3-6SHH-YLHC-ZGETD-PWNI-7NPQ-S"); + assertThat(mEsidCalculator.calculateEnterpriseId(ANOTHER_PACKAGE, + ANOTHER_ENTERPRISE_ID)).isEqualTo("LEF3-QBEC-UQ6O-RIOCX-TQF6-GRLV-F"); + } +} diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java index 9c8a38219a9c..ac9316e7d908 100644 --- a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java @@ -24,6 +24,9 @@ import static org.junit.Assert.fail; import android.net.ConnectivityMetricsEvent; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -106,6 +109,16 @@ public class NetworkWatchlistServiceTests { counter--; return true; } + + // TODO: mark @Override when aosp/1541935 automerges to master. + public void logDefaultNetworkValidity(boolean valid) { + } + + // TODO: mark @Override when aosp/1541935 automerges to master. + public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated, + LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork, + int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) { + } }; ServiceThread mHandlerThread; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java index 475e462bdd3d..009c011105de 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java @@ -31,13 +31,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import android.app.WaitResult; +import android.content.ComponentName; import android.content.pm.ActivityInfo; +import android.os.ConditionVariable; import android.platform.test.annotations.Presubmit; import android.view.Display; @@ -58,6 +62,7 @@ import java.util.concurrent.TimeUnit; @Presubmit @RunWith(WindowTestRunner.class) public class ActivityTaskSupervisorTests extends WindowTestsBase { + private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); /** * Ensures that an activity is removed from the stopping activities list once it is resumed. @@ -74,30 +79,72 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { } /** - * Ensures that waiting results are notified of launches. + * Assume an activity has been started with result code START_SUCCESS. And before it is drawn, + * it launches another existing activity. This test ensures that waiting results are notified + * or updated while the result code of next launch is TASK_TO_FRONT or DELIVERED_TO_TOP. */ @Test - public void testReportWaitingActivityLaunchedIfNeeded() { + public void testReportWaitingActivityLaunched() { final ActivityRecord firstActivity = new ActivityBuilder(mAtm) .setCreateTask(true).build(); - + final ActivityRecord secondActivity = new ActivityBuilder(mAtm) + .setCreateTask(true).build(); + final ConditionVariable condition = new ConditionVariable(); final WaitResult taskToFrontWait = new WaitResult(); - mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait); - // #notifyAll will be called on the ActivityTaskManagerService#mGlobalLock. The lock is hold - // implicitly by WindowManagerGlobalLockRule. - mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT); - - assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty(); + final ComponentName[] launchedComponent = { null }; + // Create a new thread so the waiting method in test can be notified. + new Thread(() -> { + synchronized (mAtm.mGlobalLock) { + // Note that TASK_TO_FRONT doesn't unblock the waiting thread. + mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, + START_TASK_TO_FRONT); + launchedComponent[0] = taskToFrontWait.who; + // Assume that another task is brought to front because first activity launches it. + mSupervisor.reportActivityLaunched(false /* timeout */, secondActivity, + 100 /* totalTime */, WaitResult.LAUNCH_STATE_HOT); + } + condition.open(); + }).start(); + final ActivityMetricsLogger.LaunchingState launchingState = + new ActivityMetricsLogger.LaunchingState(); + spyOn(launchingState); + doReturn(true).when(launchingState).contains(eq(secondActivity)); + // The test case already runs inside global lock, so above thread can only execute after + // this waiting method that releases the lock. + mSupervisor.waitActivityVisibleOrLaunched(taskToFrontWait, firstActivity, launchingState); + + // Assert that the thread is finished. + assertTrue(condition.block(TIMEOUT_MS)); assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT); - assertNull(taskToFrontWait.who); + assertEquals(taskToFrontWait.who, secondActivity.mActivityComponent); + assertEquals(taskToFrontWait.launchState, WaitResult.LAUNCH_STATE_HOT); + // START_TASK_TO_FRONT means that another component will be visible, so the component + // should not be assigned as the first activity. + assertNull(launchedComponent[0]); + condition.close(); final WaitResult deliverToTopWait = new WaitResult(); - mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait); - mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_DELIVERED_TO_TOP); - - assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty(); + new Thread(() -> { + synchronized (mAtm.mGlobalLock) { + // Put a noise which isn't tracked by the current wait result. The waiting procedure + // should ignore it and keep waiting for the target activity. + mSupervisor.reportActivityLaunched(false /* timeout */, mock(ActivityRecord.class), + 1000 /* totalTime */, WaitResult.LAUNCH_STATE_COLD); + // Assume that the first activity launches an existing top activity, so the waiting + // thread should be unblocked. + mSupervisor.reportWaitingActivityLaunchedIfNeeded(secondActivity, + START_DELIVERED_TO_TOP); + } + condition.open(); + }).start(); + mSupervisor.waitActivityVisibleOrLaunched(deliverToTopWait, firstActivity, launchingState); + + assertTrue(condition.block(TIMEOUT_MS)); assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP); - assertEquals(deliverToTopWait.who, firstActivity.mActivityComponent); + assertEquals(deliverToTopWait.who, secondActivity.mActivityComponent); + // The result state must be unknown because DELIVERED_TO_TOP means that the target activity + // is already visible so there is no valid launch time. + assertEquals(deliverToTopWait.launchState, WaitResult.LAUNCH_STATE_UNKNOWN); } /** @@ -202,7 +249,6 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { public void testStartHomeAfterUserUnlocked() { mSupervisor.onUserUnlocked(0); waitHandlerIdle(mAtm.mH); - verify(mRootWindowContainer, timeout(TimeUnit.SECONDS.toMillis(10))) - .startHomeOnEmptyDisplays("userUnlocked"); + verify(mRootWindowContainer, timeout(TIMEOUT_MS)).startHomeOnEmptyDisplays("userUnlocked"); } } diff --git a/services/translation/Android.bp b/services/translation/Android.bp new file mode 100644 index 000000000000..804a6177e94e --- /dev/null +++ b/services/translation/Android.bp @@ -0,0 +1,13 @@ +filegroup { + name: "services.translation-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + +java_library_static { + name: "services.translation", + defaults: ["platform_service_defaults"], + srcs: [":services.translation-sources"], + libs: ["services.core"], +}
\ No newline at end of file diff --git a/services/translation/OWNERS b/services/translation/OWNERS new file mode 100644 index 000000000000..a1e663aa8ff7 --- /dev/null +++ b/services/translation/OWNERS @@ -0,0 +1,8 @@ +# Bug component: 994311 + +adamhe@google.com +augale@google.com +joannechung@google.com +lpeter@google.com +svetoslavganov@google.com +tymtsai@google.com diff --git a/services/translation/java/com/android/server/translation/RemoteTranslationService.java b/services/translation/java/com/android/server/translation/RemoteTranslationService.java new file mode 100644 index 000000000000..0c7e61765501 --- /dev/null +++ b/services/translation/java/com/android/server/translation/RemoteTranslationService.java @@ -0,0 +1,87 @@ +/* + * 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.translation; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.service.translation.ITranslationService; +import android.service.translation.TranslationService; +import android.util.Slog; +import android.view.translation.TranslationSpec; + +import com.android.internal.infra.AbstractRemoteService; +import com.android.internal.infra.ServiceConnector; +import com.android.internal.os.IResultReceiver; + +final class RemoteTranslationService extends ServiceConnector.Impl<ITranslationService> { + + private static final String TAG = RemoteTranslationService.class.getSimpleName(); + + // TODO(b/176590870): Make PERMANENT now. + private static final long TIMEOUT_IDLE_UNBIND_MS = + AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS; + private static final int TIMEOUT_REQUEST_MS = 5_000; + + private final long mIdleUnbindTimeoutMs; + private final int mRequestTimeoutMs; + private final ComponentName mComponentName; + + RemoteTranslationService(Context context, ComponentName serviceName, + int userId, boolean bindInstantServiceAllowed) { + super(context, + new Intent(TranslationService.SERVICE_INTERFACE).setComponent(serviceName), + bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, + userId, ITranslationService.Stub::asInterface); + mIdleUnbindTimeoutMs = TIMEOUT_IDLE_UNBIND_MS; + mRequestTimeoutMs = TIMEOUT_REQUEST_MS; + mComponentName = serviceName; + + // Bind right away. + connect(); + } + + public ComponentName getComponentName() { + return mComponentName; + } + + @Override // from ServiceConnector.Impl + protected void onServiceConnectionStatusChanged(ITranslationService service, + boolean connected) { + try { + if (connected) { + service.onConnected(); + } else { + service.onDisconnected(); + } + } catch (Exception e) { + Slog.w(TAG, + "Exception calling onServiceConnectionStatusChanged(" + connected + "): ", e); + } + } + + @Override // from AbstractRemoteService + protected long getAutoDisconnectTimeoutMs() { + return mIdleUnbindTimeoutMs; + } + + public void onSessionCreated(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) { + run((s) -> s.onCreateTranslationSession(sourceSpec, destSpec, sessionId, resultReceiver)); + } +} diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java new file mode 100644 index 000000000000..e2aabe6a89ea --- /dev/null +++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.translation; + +import static android.content.Context.TRANSLATION_MANAGER_SERVICE; +import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL; + +import android.content.Context; +import android.os.RemoteException; +import android.util.Slog; +import android.view.translation.ITranslationManager; +import android.view.translation.TranslationSpec; + +import com.android.internal.os.IResultReceiver; +import com.android.server.infra.AbstractMasterSystemService; +import com.android.server.infra.FrameworkResourcesServiceNameResolver; + +/** + * Entry point service for translation management. + * + * <p>This service provides the {@link ITranslationManager} implementation and keeps a list of + * {@link TranslationManagerServiceImpl} per user; the real work is done by + * {@link TranslationManagerServiceImpl} itself. + */ +public final class TranslationManagerService + extends AbstractMasterSystemService<TranslationManagerService, + TranslationManagerServiceImpl> { + + private static final String TAG = "TranslationManagerService"; + + public TranslationManagerService(Context context) { + // TODO: Discuss the disallow policy + super(context, new FrameworkResourcesServiceNameResolver(context, + com.android.internal.R.string.config_defaultTranslationService), + /* disallowProperty */ null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER); + } + + @Override + protected TranslationManagerServiceImpl newServiceLocked(int resolvedUserId, boolean disabled) { + return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled); + } + + final class TranslationManagerServiceStub extends ITranslationManager.Stub { + @Override + public void getSupportedLocales(IResultReceiver receiver, int userId) + throws RemoteException { + synchronized (mLock) { + final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + service.getSupportedLocalesLocked(receiver); + } else { + Slog.v(TAG, "getSupportedLocales(): no service for " + userId); + receiver.send(STATUS_SYNC_CALL_FAIL, null); + } + } + } + + @Override + public void onSessionCreated(TranslationSpec sourceSpec, TranslationSpec destSpec, + int sessionId, IResultReceiver receiver, int userId) throws RemoteException { + synchronized (mLock) { + final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + service.onSessionCreatedLocked(sourceSpec, destSpec, sessionId, receiver); + } else { + Slog.v(TAG, "onSessionCreated(): no service for " + userId); + receiver.send(STATUS_SYNC_CALL_FAIL, null); + } + } + } + } + + @Override // from SystemService + public void onStart() { + publishBinderService(TRANSLATION_MANAGER_SERVICE, + new TranslationManagerService.TranslationManagerServiceStub()); + } +} diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java new file mode 100644 index 000000000000..b1f6f80d4158 --- /dev/null +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java @@ -0,0 +1,125 @@ +/* + * 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.translation; + +import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_SUCCESS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.os.RemoteException; +import android.service.translation.TranslationServiceInfo; +import android.util.Slog; +import android.view.translation.TranslationSpec; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.SyncResultReceiver; +import com.android.server.infra.AbstractPerUserSystemService; + +import java.util.ArrayList; + +final class TranslationManagerServiceImpl extends + AbstractPerUserSystemService<TranslationManagerServiceImpl, TranslationManagerService> { + + private static final String TAG = "TranslationManagerServiceImpl"; + + @GuardedBy("mLock") + @Nullable + private RemoteTranslationService mRemoteTranslationService; + + @GuardedBy("mLock") + @Nullable + private ServiceInfo mRemoteTranslationServiceInfo; + + protected TranslationManagerServiceImpl( + @NonNull TranslationManagerService master, + @NonNull Object lock, int userId, boolean disabled) { + super(master, lock, userId); + updateRemoteServiceLocked(); + } + + @GuardedBy("mLock") + @Override // from PerUserSystemService + protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) + throws PackageManager.NameNotFoundException { + final TranslationServiceInfo info = new TranslationServiceInfo(getContext(), + serviceComponent, isTemporaryServiceSetLocked(), mUserId); + mRemoteTranslationServiceInfo = info.getServiceInfo(); + return info.getServiceInfo(); + } + + @GuardedBy("mLock") + @Override // from PerUserSystemService + protected boolean updateLocked(boolean disabled) { + final boolean enabledChanged = super.updateLocked(disabled); + updateRemoteServiceLocked(); + return enabledChanged; + } + + /** + * Updates the reference to the remote service. + */ + @GuardedBy("mLock") + private void updateRemoteServiceLocked() { + if (mRemoteTranslationService != null) { + if (mMaster.debug) Slog.d(TAG, "updateRemoteService(): destroying old remote service"); + mRemoteTranslationService.unbind(); + mRemoteTranslationService = null; + } + } + + @GuardedBy("mLock") + @Nullable + private RemoteTranslationService ensureRemoteServiceLocked() { + if (mRemoteTranslationService == null) { + final String serviceName = getComponentNameLocked(); + if (serviceName == null) { + if (mMaster.verbose) { + Slog.v(TAG, "ensureRemoteServiceLocked(): no service component name."); + } + return null; + } + final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName); + mRemoteTranslationService = new RemoteTranslationService(getContext(), + serviceComponent, mUserId, /* isInstantAllowed= */ false); + } + return mRemoteTranslationService; + } + + @GuardedBy("mLock") + void getSupportedLocalesLocked(@NonNull IResultReceiver resultReceiver) { + // TODO: implement this + try { + resultReceiver.send(STATUS_SYNC_CALL_SUCCESS, + SyncResultReceiver.bundleFor(new ArrayList<>())); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException returning supported locales: " + e); + } + } + + @GuardedBy("mLock") + void onSessionCreatedLocked(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) { + final RemoteTranslationService remoteService = ensureRemoteServiceLocked(); + if (remoteService != null) { + remoteService.onSessionCreated(sourceSpec, destSpec, sessionId, resultReceiver); + } + } +} |