summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java4
-rw-r--r--core/java/android/net/ConnectivityMetricsLogger.java15
-rw-r--r--core/java/android/net/metrics/DefaultNetworkEvent.java8
-rw-r--r--core/java/android/net/metrics/DhcpClientEvent.java8
-rw-r--r--core/java/android/net/metrics/DhcpErrorEvent.java7
-rw-r--r--core/java/android/net/metrics/DnsEvent.java6
-rw-r--r--core/java/android/net/metrics/IpConnectivityEvent.java28
-rw-r--r--core/java/android/net/metrics/IpConnectivityLog.java22
-rw-r--r--core/java/android/net/metrics/IpManagerEvent.java8
-rw-r--r--core/java/android/net/metrics/IpReachabilityEvent.java10
-rw-r--r--core/java/android/net/metrics/NetworkEvent.java15
-rw-r--r--core/java/android/net/metrics/ValidationProbeEvent.java8
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/UserManager.java14
-rw-r--r--core/java/com/android/internal/util/StateMachine.java26
-rw-r--r--core/jni/android_app_ApplicationLoaders.cpp13
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java13
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java15
-rw-r--r--services/core/java/com/android/server/am/UserController.java4
-rw-r--r--services/core/java/com/android/server/connectivity/DnsEventListenerService.java24
-rw-r--r--services/core/java/com/android/server/connectivity/MetricsLoggerService.java24
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java50
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java12
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java40
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java18
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java33
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java28
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java44
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java6
-rw-r--r--services/net/java/android/net/dhcp/DhcpClient.java12
-rw-r--r--services/net/java/android/net/ip/IpManager.java6
-rw-r--r--services/net/java/android/net/ip/IpReachabilityMonitor.java13
-rw-r--r--services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java19
-rw-r--r--services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java28
-rw-r--r--services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java162
-rw-r--r--services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java197
-rw-r--r--services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java181
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java6
50 files changed, 948 insertions, 220 deletions
diff --git a/api/current.txt b/api/current.txt
index c6316271c636..08c9fd6eac1a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29362,6 +29362,7 @@ package android.os {
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(java.lang.String);
+ method public boolean isDemoUser();
method public boolean isQuietModeEnabled(android.os.UserHandle);
method public boolean isSystemUser();
method public boolean isUserAGoat();
diff --git a/api/system-current.txt b/api/system-current.txt
index 3fa518a43e49..7aa5394a9021 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -31887,6 +31887,7 @@ package android.os {
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(java.lang.String);
+ method public boolean isDemoUser();
method public boolean isManagedProfile();
method public boolean isManagedProfile(int);
method public boolean isQuietModeEnabled(android.os.UserHandle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 993f388f15ab..003e50b96533 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -29433,6 +29433,7 @@ package android.os {
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(java.lang.String);
+ method public boolean isDemoUser();
method public boolean isQuietModeEnabled(android.os.UserHandle);
method public boolean isSystemUser();
method public boolean isUserAGoat();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 8ccd5d2ebcba..d6c00589e7c2 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -723,10 +723,10 @@ public class Am extends BaseCommand {
System.out.println("Complete");
}
mRepeat--;
- if (mRepeat > 1) {
+ if (mRepeat > 0) {
mAm.unhandledBack();
}
- } while (mRepeat > 1);
+ } while (mRepeat > 0);
}
private void runForceStop() throws Exception {
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index 73734958f512..029c5bdccd41 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -23,6 +23,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
/** {@hide} */
@SystemApi
public class ConnectivityMetricsLogger {
@@ -49,8 +51,14 @@ public class ConnectivityMetricsLogger {
private int mNumSkippedEvents;
public ConnectivityMetricsLogger() {
- mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
- CONNECTIVITY_METRICS_LOGGER_SERVICE));
+ this(IConnectivityMetricsLogger.Stub.asInterface(
+ ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE)));
+ }
+
+ /** {@hide} */
+ @VisibleForTesting
+ public ConnectivityMetricsLogger(IConnectivityMetricsLogger service) {
+ mService = service;
}
/**
@@ -153,11 +161,10 @@ public class ConnectivityMetricsLogger {
public boolean unregister(PendingIntent newEventsIntent) {
try {
mService.unregister(newEventsIntent);
+ return true;
} catch (RemoteException e) {
Log.e(TAG, "IConnectivityMetricsLogger.unregister", e);
return false;
}
-
- return true;
}
}
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index f8b59925cb91..b881fbb1dacc 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -25,7 +25,7 @@ import android.os.Parcelable;
* {@hide}
*/
@SystemApi
-public final class DefaultNetworkEvent extends IpConnectivityEvent implements Parcelable {
+public final class DefaultNetworkEvent implements Parcelable {
// The ID of the network that has become the new default or NETID_UNSET if none.
public final int netId;
// The list of transport types of the new default network, for example TRANSPORT_WIFI, as
@@ -37,7 +37,8 @@ public final class DefaultNetworkEvent extends IpConnectivityEvent implements Pa
public final boolean prevIPv4;
public final boolean prevIPv6;
- private DefaultNetworkEvent(int netId, int[] transportTypes,
+ /** {@hide} */
+ public DefaultNetworkEvent(int netId, int[] transportTypes,
int prevNetId, boolean prevIPv4, boolean prevIPv6) {
this.netId = netId;
this.transportTypes = transportTypes;
@@ -105,6 +106,5 @@ public final class DefaultNetworkEvent extends IpConnectivityEvent implements Pa
public static void logEvent(
int netId, int[] transports, int prevNetId, boolean hadIPv4, boolean hadIPv6) {
- logEvent(new DefaultNetworkEvent(netId, transports, prevNetId, hadIPv4, hadIPv6));
}
-};
+}
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index ec560bf64ccc..3fe68b40e9f4 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -24,11 +24,12 @@ import android.os.Parcelable;
* {@hide}
*/
@SystemApi
-public final class DhcpClientEvent extends IpConnectivityEvent implements Parcelable {
+public final class DhcpClientEvent implements Parcelable {
public final String ifName;
public final String msg;
- private DhcpClientEvent(String ifName, String msg) {
+ /** {@hide} */
+ public DhcpClientEvent(String ifName, String msg) {
this.ifName = ifName;
this.msg = msg;
}
@@ -64,6 +65,5 @@ public final class DhcpClientEvent extends IpConnectivityEvent implements Parcel
};
public static void logStateEvent(String ifName, String state) {
- logEvent(new DhcpClientEvent(ifName, state));
}
-};
+}
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index 84795b89bb6b..4206886c6bd0 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -27,7 +27,7 @@ import com.android.internal.util.MessageUtils;
* {@hide} Event class used to record error events when parsing DHCP response packets.
*/
@SystemApi
-public final class DhcpErrorEvent extends IpConnectivityEvent implements Parcelable {
+public final class DhcpErrorEvent implements Parcelable {
public static final int L2_ERROR = 1;
public static final int L3_ERROR = 2;
public static final int L4_ERROR = 3;
@@ -61,7 +61,8 @@ public final class DhcpErrorEvent extends IpConnectivityEvent implements Parcela
// byte 3: optional code
public final int errorCode;
- private DhcpErrorEvent(String ifName, int errorCode) {
+ /** {@hide} */
+ public DhcpErrorEvent(String ifName, int errorCode) {
this.ifName = ifName;
this.errorCode = errorCode;
}
@@ -92,11 +93,9 @@ public final class DhcpErrorEvent extends IpConnectivityEvent implements Parcela
};
public static void logParseError(String ifName, int errorCode) {
- logEvent(new DhcpErrorEvent(ifName, errorCode));
}
public static void logReceiveError(String ifName) {
- logEvent(new DhcpErrorEvent(ifName, RECEIVE_ERROR));
}
public static int errorCodeWithOption(int errorCode, int option) {
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index b94dda079cd8..9eb8bdb579d0 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -24,7 +24,7 @@ import android.os.Parcelable;
* {@hide}
*/
@SystemApi
-final public class DnsEvent extends IpConnectivityEvent implements Parcelable {
+final public class DnsEvent implements Parcelable {
public final int netId;
// The event type is currently only 1 or 2, so we store it as a byte.
@@ -37,7 +37,8 @@ final public class DnsEvent extends IpConnectivityEvent implements Parcelable {
// queries.
public final int[] latenciesMs;
- private DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
+ /** {@hide} */
+ public DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
this.netId = netId;
this.eventTypes = eventTypes;
this.returnCodes = returnCodes;
@@ -82,6 +83,5 @@ final public class DnsEvent extends IpConnectivityEvent implements Parcelable {
public static void logEvent(
int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
- logEvent(new DnsEvent(netId, eventTypes, returnCodes, latenciesMs));
}
}
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
deleted file mode 100644
index d3771dcb60af..000000000000
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-import android.os.Parcelable;
-
-/** {@hide} */
-public abstract class IpConnectivityEvent {
- private static final IpConnectivityLog sMetricsLog = new IpConnectivityLog();
-
- static <T extends IpConnectivityEvent & Parcelable> void logEvent(T event) {
- sMetricsLog.log(System.currentTimeMillis(), event);
- }
-}
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 233ff74a145b..a7c1d40e90de 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -18,28 +18,40 @@ package android.net.metrics;
import android.net.ConnectivityMetricsEvent;
import android.net.ConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLogger;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Specialization of the ConnectivityMetricsLogger class for recording IP connectivity events.
* {@hide}
*/
-class IpConnectivityLog extends ConnectivityMetricsLogger {
+public class IpConnectivityLog extends ConnectivityMetricsLogger {
private static String TAG = "IpConnectivityMetricsLogger";
private static final boolean DBG = false;
+ public IpConnectivityLog() {
+ // mService initialized in super constructor.
+ }
+
+ @VisibleForTesting
+ public IpConnectivityLog(IConnectivityMetricsLogger service) {
+ super(service);
+ }
+
/**
* Log an IpConnectivity event. Contrary to logEvent(), this method does not
* keep track of skipped events and is thread-safe for callers.
*
* @param timestamp is the epoch timestamp of the event in ms.
- * @param data is a Parcelable IpConnectivityEvent instance representing the event.
+ * @param data is a Parcelable instance representing the event.
*
* @return true if the event was successfully logged.
*/
- public <T extends IpConnectivityEvent & Parcelable> boolean log(long timestamp, T data) {
+ public boolean log(long timestamp, Parcelable data) {
if (mService == null) {
if (DBG) {
Log.d(TAG, CONNECTIVITY_METRICS_LOGGER_SERVICE + " service not ready");
@@ -67,4 +79,8 @@ class IpConnectivityLog extends ConnectivityMetricsLogger {
return false;
}
}
+
+ public void log(Parcelable event) {
+ log(System.currentTimeMillis(), event);
+ }
}
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index 0940bd06c3d3..a39061748ac3 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -27,7 +27,7 @@ import com.android.internal.util.MessageUtils;
* {@hide}
*/
@SystemApi
-public final class IpManagerEvent extends IpConnectivityEvent implements Parcelable {
+public final class IpManagerEvent implements Parcelable {
public static final int PROVISIONING_OK = 1;
public static final int PROVISIONING_FAIL = 2;
@@ -37,7 +37,8 @@ public final class IpManagerEvent extends IpConnectivityEvent implements Parcela
public final int eventType;
public final long durationMs;
- private IpManagerEvent(String ifName, int eventType, long duration) {
+ /** {@hide} */
+ public IpManagerEvent(String ifName, int eventType, long duration) {
this.ifName = ifName;
this.eventType = eventType;
this.durationMs = duration;
@@ -71,7 +72,6 @@ public final class IpManagerEvent extends IpConnectivityEvent implements Parcela
};
public static void logEvent(int eventType, String ifName, long durationMs) {
- logEvent(new IpManagerEvent(ifName, eventType, durationMs));
}
@Override
@@ -84,4 +84,4 @@ public final class IpManagerEvent extends IpConnectivityEvent implements Parcela
static final SparseArray<String> constants = MessageUtils.findMessageNames(
new Class[]{IpManagerEvent.class}, new String[]{"PROVISIONING_", "COMPLETE_"});
}
-};
+}
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index d40389c03986..7d0229191563 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -27,7 +27,7 @@ import com.android.internal.util.MessageUtils;
* {@hide}
*/
@SystemApi
-public final class IpReachabilityEvent extends IpConnectivityEvent implements Parcelable {
+public final class IpReachabilityEvent implements Parcelable {
public static final int PROBE = 1 << 8;
public static final int NUD_FAILED = 2 << 8;
@@ -41,7 +41,8 @@ public final class IpReachabilityEvent extends IpConnectivityEvent implements Pa
// byte 3: kernel errno from RTNetlink or IpReachabilityMonitor
public final int eventType;
- private IpReachabilityEvent(String ifName, int eventType) {
+ /** {@hide} */
+ public IpReachabilityEvent(String ifName, int eventType) {
this.ifName = ifName;
this.eventType = eventType;
}
@@ -72,15 +73,12 @@ public final class IpReachabilityEvent extends IpConnectivityEvent implements Pa
};
public static void logProbeEvent(String ifName, int nlErrorCode) {
- logEvent(new IpReachabilityEvent(ifName, PROBE | (nlErrorCode & 0xFF)));
}
public static void logNudFailed(String ifName) {
- logEvent(new IpReachabilityEvent(ifName, NUD_FAILED));
}
public static void logProvisioningLost(String ifName) {
- logEvent(new IpReachabilityEvent(ifName, PROVISIONING_LOST));
}
@Override
@@ -94,4 +92,4 @@ public final class IpReachabilityEvent extends IpConnectivityEvent implements Pa
MessageUtils.findMessageNames(new Class[]{IpReachabilityEvent.class},
new String[]{"PROBE", "PROVISIONING_", "NUD_"});
}
-};
+}
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 08c9c758bbc8..cdfe386d430c 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -27,7 +27,7 @@ import com.android.internal.util.MessageUtils;
* {@hide}
*/
@SystemApi
-public final class NetworkEvent extends IpConnectivityEvent implements Parcelable {
+public final class NetworkEvent implements Parcelable {
public static final int NETWORK_CONNECTED = 1;
public static final int NETWORK_VALIDATED = 2;
@@ -41,12 +41,18 @@ public final class NetworkEvent extends IpConnectivityEvent implements Parcelabl
public final int eventType;
public final long durationMs;
- private NetworkEvent(int netId, int eventType, long durationMs) {
+ /** {@hide} */
+ public NetworkEvent(int netId, int eventType, long durationMs) {
this.netId = netId;
this.eventType = eventType;
this.durationMs = durationMs;
}
+ /** {@hide} */
+ public NetworkEvent(int netId, int eventType) {
+ this(netId, eventType, 0);
+ }
+
private NetworkEvent(Parcel in) {
netId = in.readInt();
eventType = in.readInt();
@@ -75,15 +81,12 @@ public final class NetworkEvent extends IpConnectivityEvent implements Parcelabl
};
public static void logEvent(int netId, int eventType) {
- logEvent(new NetworkEvent(netId, eventType, 0));
}
public static void logValidated(int netId, long durationMs) {
- logEvent(new NetworkEvent(netId, NETWORK_VALIDATED, durationMs));
}
public static void logCaptivePortalFound(int netId, long durationMs) {
- logEvent(new NetworkEvent(netId, NETWORK_CAPTIVE_PORTAL_FOUND, durationMs));
}
@Override
@@ -96,4 +99,4 @@ public final class NetworkEvent extends IpConnectivityEvent implements Parcelabl
static final SparseArray<String> constants = MessageUtils.findMessageNames(
new Class[]{NetworkEvent.class}, new String[]{"NETWORK_"});
}
-};
+}
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 751c35f8a144..d5ad0f6c25a9 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -27,7 +27,7 @@ import com.android.internal.util.MessageUtils;
* {@hide}
*/
@SystemApi
-public final class ValidationProbeEvent extends IpConnectivityEvent implements Parcelable {
+public final class ValidationProbeEvent implements Parcelable {
public static final int PROBE_DNS = 0;
public static final int PROBE_HTTP = 1;
@@ -42,7 +42,8 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
public final int probeType;
public final int returnCode;
- private ValidationProbeEvent(int netId, long durationMs, int probeType, int returnCode) {
+ /** @hide */
+ public ValidationProbeEvent(int netId, long durationMs, int probeType, int returnCode) {
this.netId = netId;
this.durationMs = durationMs;
this.probeType = probeType;
@@ -84,7 +85,6 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
}
public static void logEvent(int netId, long durationMs, int probeType, int returnCode) {
- logEvent(new ValidationProbeEvent(netId, durationMs, probeType, returnCode));
}
@Override
@@ -97,4 +97,4 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
static final SparseArray<String> constants = MessageUtils.findMessageNames(
new Class[]{ValidationProbeEvent.class}, new String[]{"PROBE_"});
}
-};
+}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index b27cb32bd4eb..eeb641d33c20 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -81,4 +81,5 @@ interface IUserManager {
void clearSeedAccountData();
boolean someUserHasSeedAccount(in String accountName, in String accountType);
boolean isManagedProfile(int userId);
+ boolean isDemoUser(int userId);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d74220676ca2..a44a9eed701b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -859,15 +859,17 @@ public class UserManager {
}
/**
- * Checks if the calling app is running in a demo user.
- * <p>
- * Caller must hold the MANAGE_USERS permission.
+ * Checks if the calling app is running in a demo user. When running in a demo user,
+ * apps can be more helpful to the user, or explain their features in more detail.
+ *
* @return whether the caller is a demo user.
- * @hide
*/
public boolean isDemoUser() {
- UserInfo user = getUserInfo(UserHandle.myUserId());
- return user != null && user.isDemo();
+ try {
+ return mService.isDemoUser(UserHandle.myUserId());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
/**
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 39fd36b9058c..a5a3dba7ac12 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -29,8 +29,8 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
-import java.util.Iterator;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Vector;
/**
@@ -1642,7 +1642,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what) {
+ public void sendMessage(int what) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1655,7 +1655,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, Object obj) {
+ public void sendMessage(int what, Object obj) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1668,7 +1668,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, int arg1) {
+ public void sendMessage(int what, int arg1) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1681,7 +1681,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, int arg1, int arg2) {
+ public void sendMessage(int what, int arg1, int arg2) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1694,7 +1694,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, int arg1, int arg2, Object obj) {
+ public void sendMessage(int what, int arg1, int arg2, Object obj) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1707,7 +1707,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(Message msg) {
+ public void sendMessage(Message msg) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1720,7 +1720,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, long delayMillis) {
+ public void sendMessageDelayed(int what, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1733,7 +1733,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
+ public void sendMessageDelayed(int what, Object obj, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1746,7 +1746,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, int arg1, long delayMillis) {
+ public void sendMessageDelayed(int what, int arg1, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1759,7 +1759,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, int arg1, int arg2, long delayMillis) {
+ public void sendMessageDelayed(int what, int arg1, int arg2, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1772,7 +1772,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, int arg1, int arg2, Object obj,
+ public void sendMessageDelayed(int what, int arg1, int arg2, Object obj,
long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
@@ -1786,7 +1786,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(Message msg, long delayMillis) {
+ public void sendMessageDelayed(Message msg, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
diff --git a/core/jni/android_app_ApplicationLoaders.cpp b/core/jni/android_app_ApplicationLoaders.cpp
index 24ee9591fc2f..3e7c039e2129 100644
--- a/core/jni/android_app_ApplicationLoaders.cpp
+++ b/core/jni/android_app_ApplicationLoaders.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "ApplicationLoaders"
+
#include <nativehelper/ScopedUtfChars.h>
#include <nativeloader/native_loader.h>
#include <vulkan/vulkan_loader_data.h>
@@ -22,10 +24,17 @@
static void setupVulkanLayerPath_native(JNIEnv* env, jobject clazz,
jobject classLoader, jstring librarySearchPath) {
+ android_namespace_t* ns = android::FindNamespaceByClassLoader(env, classLoader);
ScopedUtfChars layerPathChars(env, librarySearchPath);
+
vulkan::LoaderData& loader_data = vulkan::LoaderData::GetInstance();
- loader_data.layer_path = layerPathChars.c_str();
- loader_data.app_namespace = android::FindNamespaceByClassLoader(env, classLoader);
+ if (loader_data.layer_path.empty()) {
+ loader_data.layer_path = layerPathChars.c_str();
+ loader_data.app_namespace = ns;
+ } else {
+ ALOGD("ignored Vulkan layer search path %s for namespace %p",
+ layerPathChars.c_str(), ns);
+ }
}
static const JNINativeMethod g_methods[] = {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3783dc8fa179..3c71dd9312a5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -193,6 +193,7 @@
<protected-broadcast android:name="android.btopp.intent.action.OPEN" />
<protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
<protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
+ <protected-broadcast android:name="com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN" />
<protected-broadcast android:name="com.android.bluetooth.pbap.authchall" />
<protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
<protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ae2a9e4e1b4e..a32faf8a8bce 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4382,7 +4382,7 @@
<!-- Title of the dialog shown when user inactivity times out in retail demo mode [CHAR LIMIT=40] -->
<string name="demo_user_inactivity_timeout_title">Reset device?</string>
<!-- Warning message shown when user inactivity times out in retail demo mode [CHAR LIMIT=none] -->
- <string name="demo_user_inactivity_timeout_countdown">You\'ll lose any changes and the demo will start again in <xliff:g id="timeout" example="9">%1$s</xliff:g> seconds\u2026</string>
+ <string name="demo_user_inactivity_timeout_countdown">You\u2019ll lose any changes and the demo will start again in <xliff:g id="timeout" example="9">%1$s</xliff:g> seconds\u2026</string>
<!-- Text of button to allow user to abort countdown and continue current session in retail demo mode [CHAR LIMIT=40] -->
<string name="demo_user_inactivity_timeout_left_button">Cancel</string>
<!-- Text of button to allow user to abort countdown and immediately start another session in retail demo mode [CHAR LIMIT=40] -->
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index a8c87370e18b..c34f474762f0 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -243,7 +243,9 @@ public class VectorDrawable extends Drawable {
* constructors to set the state and initialize local properties.
*/
private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) {
- mVectorState = state;
+ // Constant state sharing is disabled until we fix onStateChanged()
+ // affecting the shared bitmap.
+ mVectorState = new VectorDrawableState(state);
updateLocalState(res);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 7993131e60ec..548ddf8aeb28 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -16,6 +16,7 @@ import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
import android.os.UserManager;
+import android.print.PrintManager;
import com.android.internal.util.UserIcons;
import com.android.settingslib.drawable.UserIconDrawable;
@@ -185,7 +186,8 @@ public class Utils {
&& sSystemSignature[0].equals(getFirstSignature(pkg)))
|| pkg.packageName.equals(sPermissionControllerPackageName)
|| pkg.packageName.equals(sServicesSystemSharedLibPackageName)
- || pkg.packageName.equals(sSharedSystemSharedLibPackageName);
+ || pkg.packageName.equals(sSharedSystemSharedLibPackageName)
+ || pkg.packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
}
private static Signature getFirstSignature(PackageInfo pkg) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index b20f46f6b1f5..7e1deec3429a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -184,7 +184,9 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
null, false);
reloadResources();
+ }
+ public void onBootCompleted() {
// When we start, preload the data associated with the previous recent tasks.
// We can use a new plan since the caches will be the same.
RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -197,10 +199,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
loader.loadTasks(mContext, plan, launchOpts);
}
- public void onBootCompleted() {
- // Do nothing
- }
-
public void onConfigurationChanged() {
reloadResources();
mDummyStackView.reloadOnConfigurationChange();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 94231c6403b0..37a4948ae8b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -314,8 +314,12 @@ public class SystemServicesProxy {
if (includeFrontMostExcludedTask) {
flags |= ActivityManager.RECENT_WITH_EXCLUDED;
}
- List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
- flags, userId);
+ List<ActivityManager.RecentTaskInfo> tasks = null;
+ try {
+ tasks = mAm.getRecentTasksForUser(numTasksToQuery, flags, userId);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to get recent tasks", e);
+ }
// Break early if we can't get a valid set of tasks
if (tasks == null) {
@@ -330,8 +334,9 @@ public class SystemServicesProxy {
// NOTE: The order of these checks happens in the expected order of the traversal of the
// tasks
- // Remove the task if it is blacklisted
- if (sRecentsBlacklist.contains(t.realActivity.getClassName())) {
+ // Remove the task if it or it's package are blacklsited
+ if (sRecentsBlacklist.contains(t.realActivity.getClassName()) ||
+ sRecentsBlacklist.contains(t.realActivity.getPackageName())) {
iter.remove();
continue;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 44b8d3d83df8..1a7a2bf88a88 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -76,6 +76,7 @@ import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
import android.net.metrics.DefaultNetworkEvent;
+import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.os.Binder;
import android.os.Build;
@@ -454,6 +455,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+
/**
* Implements support for the legacy "one network per network type" model.
*
@@ -2205,7 +2208,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void linger(NetworkAgentInfo nai) {
nai.lingering = true;
- NetworkEvent.logEvent(nai.network.netId, NetworkEvent.NETWORK_LINGER);
+ logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER);
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING);
}
@@ -2219,7 +2222,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.networkLingered.clear();
if (!nai.lingering) return;
nai.lingering = false;
- NetworkEvent.logEvent(nai.network.netId, NetworkEvent.NETWORK_UNLINGER);
+ logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
if (VDBG) log("Canceling linger of " + nai.name());
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
}
@@ -5242,7 +5245,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return new NetworkMonitor(context, handler, nai, defaultRequest);
}
- private static void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
+ private void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
int newNetid = NETID_UNSET;
int prevNetid = NETID_UNSET;
int[] transports = new int[0];
@@ -5260,6 +5263,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
}
- DefaultNetworkEvent.logEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6);
+ mMetricsLog.log(new DefaultNetworkEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6));
+ }
+
+ private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
+ mMetricsLog.log(new NetworkEvent(nai.network.netId, evtype));
}
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6b44f14883e5..d25f2cb76d74 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -99,6 +99,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
@@ -1057,6 +1058,7 @@ final class UserController {
uss.switching = true;
mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks;
}
+ final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount);
for (int i = 0; i < observerCount; i++) {
try {
// Prepend with unique prefix to guarantee that keys are unique
@@ -1075,7 +1077,7 @@ final class UserController {
}
curWaitingUserSwitchCallbacks.remove(name);
// Continue switching if all callbacks have been notified
- if (curWaitingUserSwitchCallbacks.isEmpty()) {
+ if (waitingCallbacksCount.decrementAndGet() == 0) {
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
diff --git a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java b/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
index 18ab73100b81..8d206ef90b94 100644
--- a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
@@ -17,15 +17,17 @@
package com.android.server.connectivity;
import android.content.Context;
-import android.net.metrics.DnsEvent;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkRequest;
+import android.net.metrics.DnsEvent;
import android.net.metrics.IDnsEventListener;
+import android.net.metrics.IpConnectivityLog;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import java.io.PrintWriter;
@@ -45,12 +47,13 @@ public class DnsEventListenerService extends IDnsEventListener.Stub {
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ // TODO: read this constant from system property
private static final int MAX_LOOKUPS_PER_DNS_EVENT = 100;
// Stores the results of a number of consecutive DNS lookups on the same network.
// This class is not thread-safe and it is the responsibility of the service to call its methods
// on one thread at a time.
- private static class DnsEventBatch {
+ private class DnsEventBatch {
private final int mNetId;
private final byte[] mEventTypes = new byte[MAX_LOOKUPS_PER_DNS_EVENT];
@@ -82,7 +85,7 @@ public class DnsEventListenerService extends IDnsEventListener.Stub {
byte[] eventTypes = Arrays.copyOf(mEventTypes, mEventCount);
byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount);
int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount);
- DnsEvent.logEvent(mNetId, eventTypes, returnCodes, latenciesMs);
+ mMetricsLog.log(new DnsEvent(mNetId, eventTypes, returnCodes, latenciesMs));
maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId));
mEventCount = 0;
}
@@ -96,13 +99,14 @@ public class DnsEventListenerService extends IDnsEventListener.Stub {
// Only sorted for ease of debugging. Because we only typically have a handful of networks up
// at any given time, performance is not a concern.
@GuardedBy("this")
- private SortedMap<Integer, DnsEventBatch> mEventBatches = new TreeMap<>();
+ private final SortedMap<Integer, DnsEventBatch> mEventBatches = new TreeMap<>();
// We register a NetworkCallback to ensure that when a network disconnects, we flush the DNS
// queries we've logged on that network. Because we do not do this periodically, we might lose
// up to MAX_LOOKUPS_PER_DNS_EVENT lookup stats on each network when the system is shutting
// down. We believe this to be sufficient for now.
private final ConnectivityManager mCm;
+ private final IpConnectivityLog mMetricsLog;
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
public void onLost(Network network) {
@@ -116,11 +120,15 @@ public class DnsEventListenerService extends IDnsEventListener.Stub {
};
public DnsEventListenerService(Context context) {
+ this(context.getSystemService(ConnectivityManager.class), new IpConnectivityLog());
+ }
+
+ @VisibleForTesting
+ public DnsEventListenerService(ConnectivityManager cm, IpConnectivityLog log) {
// We are started when boot is complete, so ConnectivityService should already be running.
- final NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .build();
- mCm = context.getSystemService(ConnectivityManager.class);
+ mCm = cm;
+ mMetricsLog = log;
+ final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
mCm.registerNetworkCallback(request, mNetworkCallback);
}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index 69ef30fbe66a..05f1a6e6a3a4 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;
import android.app.PendingIntent;
@@ -60,17 +61,11 @@ public class MetricsLoggerService extends SystemService {
}
}
- // TODO: read from system property
- private final int MAX_NUMBER_OF_EVENTS = 1000;
-
- // TODO: read from system property
- private final int EVENTS_NOTIFICATION_THRESHOLD = 300;
-
- // TODO: read from system property
- private final int THROTTLING_TIME_INTERVAL_MILLIS = 60 * 60 * 1000; // 1 hour
-
- // TODO: read from system property
+ // TODO: read these constants from system property
+ private final int EVENTS_NOTIFICATION_THRESHOLD = 300;
+ private final int MAX_NUMBER_OF_EVENTS = 1000;
private final int THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT = 1000;
+ private final long THROTTLING_TIME_INTERVAL_MILLIS = DateUtils.HOUR_IN_MILLIS;
private int mEventCounter = 0;
@@ -127,10 +122,13 @@ public class MetricsLoggerService extends SystemService {
mEvents.addLast(e);
}
+ @VisibleForTesting
+ final MetricsLoggerImpl mBinder = new MetricsLoggerImpl();
+
/**
* Implementation of the IConnectivityMetricsLogger interface.
*/
- private final IConnectivityMetricsLogger.Stub mBinder = new IConnectivityMetricsLogger.Stub() {
+ final class MetricsLoggerImpl extends IConnectivityMetricsLogger.Stub {
private final ArrayList<PendingIntent> mPendingIntents = new ArrayList<>();
@@ -223,7 +221,9 @@ public class MetricsLoggerService extends SystemService {
}
pw.println();
- mDnsListener.dump(pw);
+ if (mDnsListener != null) {
+ mDnsListener.dump(pw);
+ }
}
public long logEvent(ConnectivityMetricsEvent event) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ddaebfa0e747..eeddff53e8ce 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -34,8 +34,9 @@ import android.net.NetworkRequest;
import android.net.ProxyInfo;
import android.net.TrafficStats;
import android.net.Uri;
-import android.net.metrics.ValidationProbeEvent;
+import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
+import android.net.metrics.ValidationProbeEvent;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.util.Stopwatch;
@@ -230,6 +231,7 @@ public class NetworkMonitor extends StateMachine {
private final WifiManager mWifiManager;
private final AlarmManager mAlarmManager;
private final NetworkRequest mDefaultRequest;
+ private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
private boolean mIsCaptivePortalCheckEnabled;
private boolean mUseHttps;
@@ -311,11 +313,11 @@ public class NetworkMonitor extends StateMachine {
transitionTo(mLingeringState);
return HANDLED;
case CMD_NETWORK_CONNECTED:
- NetworkEvent.logEvent(mNetId, NetworkEvent.NETWORK_CONNECTED);
+ logNetworkEvent(NetworkEvent.NETWORK_CONNECTED);
transitionTo(mEvaluatingState);
return HANDLED;
case CMD_NETWORK_DISCONNECTED:
- NetworkEvent.logEvent(mNetId, NetworkEvent.NETWORK_DISCONNECTED);
+ logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED);
if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
mLaunchCaptivePortalAppBroadcastReceiver = null;
@@ -380,10 +382,7 @@ public class NetworkMonitor extends StateMachine {
private class ValidatedState extends State {
@Override
public void enter() {
- if (mEvaluationTimer.isRunning()) {
- NetworkEvent.logValidated(mNetId, mEvaluationTimer.stop());
- mEvaluationTimer.reset();
- }
+ maybeLogEvaluationResult(NetworkEvent.NETWORK_VALIDATED);
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
}
@@ -530,7 +529,7 @@ public class NetworkMonitor extends StateMachine {
} else {
final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
sendMessageDelayed(msg, mReevaluateDelayMs);
- NetworkEvent.logEvent(mNetId, NetworkEvent.NETWORK_VALIDATION_FAILED);
+ logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
mConnectivityServiceHandler.sendMessage(obtainMessage(
EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
probeResult.mRedirectUrl));
@@ -590,10 +589,7 @@ public class NetworkMonitor extends StateMachine {
@Override
public void enter() {
- if (mEvaluationTimer.isRunning()) {
- NetworkEvent.logCaptivePortalFound(mNetId, mEvaluationTimer.stop());
- mEvaluationTimer.reset();
- }
+ maybeLogEvaluationResult(NetworkEvent.NETWORK_CAPTIVE_PORTAL_FOUND);
// Don't annoy user with sign-in notifications.
if (mDontDisplaySigninNotification) return;
// Create a CustomIntentReceiver that sends us a
@@ -758,11 +754,12 @@ public class NetworkMonitor extends StateMachine {
if (!TextUtils.isEmpty(hostToResolve)) {
String probeName = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
final Stopwatch dnsTimer = new Stopwatch().start();
+ int dnsResult;
+ long dnsLatency;
try {
InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(hostToResolve);
- long dnsLatency = dnsTimer.stop();
- ValidationProbeEvent.logEvent(mNetId, dnsLatency,
- ValidationProbeEvent.PROBE_DNS, ValidationProbeEvent.DNS_SUCCESS);
+ dnsResult = ValidationProbeEvent.DNS_SUCCESS;
+ dnsLatency = dnsTimer.stop();
final StringBuffer connectInfo = new StringBuffer(", " + hostToResolve + "=");
for (InetAddress address : addresses) {
connectInfo.append(address.getHostAddress());
@@ -770,11 +767,11 @@ public class NetworkMonitor extends StateMachine {
}
validationLog(probeName + " OK " + dnsLatency + "ms" + connectInfo);
} catch (UnknownHostException e) {
- long dnsLatency = dnsTimer.stop();
- ValidationProbeEvent.logEvent(mNetId, dnsLatency,
- ValidationProbeEvent.PROBE_DNS, ValidationProbeEvent.DNS_FAILURE);
+ dnsResult = ValidationProbeEvent.DNS_FAILURE;
+ dnsLatency = dnsTimer.stop();
validationLog(probeName + " FAIL " + dnsLatency + "ms, " + hostToResolve);
}
+ logValidationProbe(dnsLatency, ValidationProbeEvent.PROBE_DNS, dnsResult);
}
CaptivePortalProbeResult result;
@@ -855,7 +852,7 @@ public class NetworkMonitor extends StateMachine {
urlConnection.disconnect();
}
}
- ValidationProbeEvent.logEvent(mNetId, probeTimer.stop(), probeType, httpResponseCode);
+ logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
}
@@ -1012,4 +1009,19 @@ public class NetworkMonitor extends StateMachine {
protected WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int i) {
return new WakeupMessage(c, h, s, i);
}
+
+ private void logNetworkEvent(int evtype) {
+ mMetricsLog.log(new NetworkEvent(mNetId, evtype));
+ }
+
+ private void maybeLogEvaluationResult(int evtype) {
+ if (mEvaluationTimer.isRunning()) {
+ mMetricsLog.log(new NetworkEvent(mNetId, evtype, mEvaluationTimer.stop()));
+ mEvaluationTimer.reset();
+ }
+ }
+
+ private void logValidationProbe(long durationMs, int probeType, int probeResult) {
+ mMetricsLog.log(new ValidationProbeEvent(mNetId, durationMs, probeType, probeResult));
+ }
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 14e4bc66199d..be8e300c9352 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1019,14 +1019,12 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
}
+ /***
+ * @param opPackageName the name of the calling package
+ * @return authenticator id for the current user
+ */
public long getAuthenticatorId(String opPackageName) {
- if (canUseFingerprint(opPackageName, false /* foregroundOnly */,
- Binder.getCallingUid(), Binder.getCallingPid())) {
- return mCurrentAuthenticatorId;
- } else {
- Slog.w(TAG, "Client isn't current, returning authenticator_id=0");
- }
- return 0;
+ return mCurrentAuthenticatorId;
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 21bcacd3e9a7..1206263fb281 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1997,6 +1997,7 @@ public class NotificationManagerService extends SystemService {
android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
return;
}
+ checkCallerIsSameApp(pkg);
if (!checkPolicyAccess(pkg)) {
Slog.w(TAG, "Notification policy access denied calling " + method);
throw new SecurityException("Notification policy access denied");
@@ -3655,6 +3656,10 @@ public class NotificationManagerService extends SystemService {
if (isCallerSystem()) {
return;
}
+ checkCallerIsSameApp(pkg);
+ }
+
+ private static void checkCallerIsSameApp(String pkg) {
final int uid = Binder.getCallingUid();
try {
ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a30422d7713f..114ad968d6dc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -629,7 +629,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final ProtectedPackages mProtectedPackages;
- boolean mRestoredSettings;
+ boolean mFirstBoot;
// System configuration read by SystemConfig.
final int[] mGlobalGids;
@@ -2222,6 +2222,34 @@ public class PackageManagerService extends IPackageManager.Stub {
displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
}
+ /**
+ * Requests that files preopted on a secondary system partition be copied to the data partition
+ * if possible. Note that the actual copying of the files is accomplished by init for security
+ * reasons. This simply requests that the copy takes place and awaits confirmation of its
+ * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy.
+ */
+ private static void requestCopyPreoptedFiles() {
+ final int WAIT_TIME_MS = 100;
+ final String CP_PREOPT_PROPERTY = "sys.cppreopt";
+ if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
+ SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
+ // We will wait for up to 100 seconds.
+ final long timeEnd = SystemClock.uptimeMillis() + 100 * 1000;
+ while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
+ try {
+ Thread.sleep(WAIT_TIME_MS);
+ } catch (InterruptedException e) {
+ // Do nothing
+ }
+ if (SystemClock.uptimeMillis() > timeEnd) {
+ SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
+ Slog.wtf(TAG, "cppreopt did not finish!");
+ break;
+ }
+ }
+ }
+ }
+
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -2325,7 +2353,11 @@ public class PackageManagerService extends IPackageManager.Stub {
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
- mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));
+ mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
+
+ if (mFirstBoot) {
+ requestCopyPreoptedFiles();
+ }
String customResolverActivity = Resources.getSystem().getString(
R.string.config_customResolverActivity);
@@ -2702,7 +2734,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// If this is the first boot or an update from pre-M, and it is a normal
// boot, then we need to initialize the default preferred apps across
// all defined users.
- if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
+ if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(this, user.id);
applyFactoryDefaultBrowserLPw(user.id);
@@ -2860,7 +2892,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public boolean isFirstBoot() {
- return !mRestoredSettings;
+ return mFirstBoot;
}
@Override
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d128252e8063..bbffd328eecd 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -456,7 +456,6 @@ public class UserManagerService extends IUserManager.Stub {
setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
}
- maybeInitializeDemoMode(UserHandle.USER_SYSTEM);
mContext.registerReceiver(mDisableQuietModeCallback,
new IntentFilter(ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK),
null, mHandler);
@@ -869,12 +868,25 @@ public class UserManagerService extends IUserManager.Stub {
}
}
synchronized (mUsersLock) {
- UserInfo userInfo = getUserInfoLU(userId);
+ UserInfo userInfo = getUserInfoLU(userId);
return userInfo != null && userInfo.isManagedProfile();
}
}
@Override
+ public boolean isDemoUser(int userId) {
+ int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId != userId && !hasManageUsersPermission()) {
+ throw new SecurityException("You need MANAGE_USERS permission to query if u=" + userId
+ + " is a demo user");
+ }
+ synchronized (mUsersLock) {
+ UserInfo userInfo = getUserInfoLU(userId);
+ return userInfo != null && userInfo.isDemo();
+ }
+ }
+
+ @Override
public boolean isRestricted() {
synchronized (mUsersLock) {
return getUserInfoLU(UserHandle.getCallingUserId()).isRestricted();
@@ -2901,7 +2913,7 @@ public class UserManagerService extends IUserManager.Stub {
}
private void maybeInitializeDemoMode(int userId) {
- if (UserManager.isDeviceInDemoMode(mContext)) {
+ if (UserManager.isDeviceInDemoMode(mContext) && userId != UserHandle.USER_SYSTEM) {
String demoLauncher =
mContext.getResources().getString(
com.android.internal.R.string.config_demoModeLauncherComponent);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index edcc32e5b587..b9cb38b242c0 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -134,6 +134,9 @@ class AppWindowToken extends WindowToken {
boolean mAppStopped;
int mPendingRelaunchCount;
+ private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds =
+ new ArrayList<WindowSurfaceController.SurfaceControlWithBackground>();
+
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
@@ -734,6 +737,36 @@ class AppWindowToken extends WindowToken {
service.mWindowPlacerLocked.performSurfacePlacement();
}
+ void addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
+ mSurfaceViewBackgrounds.add(background);
+ }
+
+ void removeSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
+ mSurfaceViewBackgrounds.remove(background);
+ updateSurfaceViewBackgroundVisibilities();
+ }
+
+ // We use DimLayers behind SurfaceViews to prevent holes while resizing and creating.
+ // However, we need to ensure one SurfaceView doesn't cover another when they are both placed
+ // below the main app window (as traditionally a SurfaceView which is never drawn
+ // to is totally translucent). So we look at all our SurfaceView backgrounds and only enable
+ // the background for the SurfaceView with lowest Z order
+ void updateSurfaceViewBackgroundVisibilities() {
+ WindowSurfaceController.SurfaceControlWithBackground bottom = null;
+ int bottomLayer = Integer.MAX_VALUE;
+ for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
+ WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
+ if (sc.mVisible && sc.mLayer < bottomLayer) {
+ bottomLayer = sc.mLayer;
+ bottom = sc;
+ }
+ }
+ for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
+ WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
+ sc.updateBackgroundVisibility(sc != bottom);
+ }
+ }
+
@Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 88028befdf1e..18f97a7f606f 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -479,6 +479,8 @@ class WallpaperController {
boolean resetTopWallpaper = false;
boolean inFreeformSpace = false;
boolean replacing = false;
+ boolean keyguardGoingAwayWithWallpaper = false;
+
for (int i = windows.size() - 1; i >= 0; i--) {
w = windows.get(i);
if ((w.mAttrs.type == TYPE_WALLPAPER)) {
@@ -506,13 +508,11 @@ class WallpaperController {
inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
}
- replacing = replacing || w.mWillReplaceWindow;
+ replacing |= w.mWillReplaceWindow;
+ keyguardGoingAwayWithWallpaper |= (w.mAppToken != null
+ && w.mWinAnimator.mKeyguardGoingAwayWithWallpaper);
- // If the app is executing an animation because the keyguard is going away (and the
- // keyguard was showing the wallpaper) keep the wallpaper during the animation so it
- // doesn't flicker out.
- final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
- || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayWithWallpaper);
+ final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
result.setWallpaperTarget(w, i);
@@ -529,18 +529,26 @@ class WallpaperController {
}
}
- if (result.wallpaperTarget == null && windowDetachedI >= 0) {
+ if (result.wallpaperTarget != null) {
+ return;
+ }
+
+ if (windowDetachedI >= 0) {
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
"Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w);
result.setWallpaperTarget(w, windowDetachedI);
- }
- if (result.wallpaperTarget == null
- && (inFreeformSpace || (replacing && mWallpaperTarget != null))) {
+ } else if (inFreeformSpace || (replacing && mWallpaperTarget != null)) {
// In freeform mode we set the wallpaper as its own target, so we don't need an
// additional window to make it visible. When we are replacing a window and there was
// wallpaper before replacement, we want to keep the window until the new windows fully
// appear and can determine the visibility, to avoid flickering.
result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
+
+ } else if (keyguardGoingAwayWithWallpaper) {
+ // If the app is executing an animation because the keyguard is going away (and the
+ // keyguard was showing the wallpaper) keep the wallpaper during the animation so it
+ // doesn't flicker out by having it be its own target.
+ result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b8accf547686..84173d26ef8b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3003,8 +3003,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (win.isWinVisibleLw() && !winAnimator.isAnimationSet()
- && winAnimator.applyAnimationLocked(transit, false)) {
+ if (win.isWinVisibleLw() && (winAnimator.isAnimationSet() ||
+ winAnimator.applyAnimationLocked(transit, false))) {
focusMayChange = isDefaultDisplay;
win.mAnimatingExit = true;
win.mWinAnimator.mAnimating = true;
@@ -3170,6 +3170,7 @@ public class WindowManagerService extends IWindowManager.Stub
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
// is running.
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
if (okToDisplay()) {
DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
final int width = displayInfo.appWidth;
@@ -3221,6 +3222,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else {
atoken.mAppAnimator.clearAnimation();
}
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
return atoken.mAppAnimator.animation != null;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6c554954c6dc..e374ee91389f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -55,6 +55,7 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.os.Debug;
import android.os.RemoteException;
+import android.os.Trace;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.MagnificationSpec;
@@ -1863,6 +1864,7 @@ class WindowStateAnimator {
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
// is running.
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#applyAnimationLocked");
if (mService.okToDisplay()) {
int anim = mPolicy.selectAnimationLw(mWin, transit);
int attr = -1;
@@ -1902,6 +1904,8 @@ class WindowStateAnimator {
} else {
clearAnimation();
}
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+
if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
mService.adjustForImeIfNeeded(mWin.mDisplayContent);
if (isEntrance) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 3121415c4811..c77e5725a707 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -84,9 +84,10 @@ class WindowSurfaceController {
// to a black-out layer placed one Z-layer below the surface.
// This prevents holes to whatever app/wallpaper is underneath.
if (animator.mWin.isChildWindow() &&
- animator.mWin.mSubLayer < 0) {
+ animator.mWin.mSubLayer < 0 &&
+ animator.mWin.mAppToken != null) {
mSurfaceControl = new SurfaceControlWithBackground(s,
- name, w, h, format, flags);
+ name, w, h, format, flags, animator.mWin.mAppToken);
} else if (DEBUG_SURFACE_TRACE) {
mSurfaceControl = new SurfaceTrace(
s, name, w, h, format, flags);
@@ -758,18 +759,25 @@ class WindowSurfaceController {
}
}
- private static class SurfaceControlWithBackground extends SurfaceControl {
+ class SurfaceControlWithBackground extends SurfaceControl {
private SurfaceControl mBackgroundControl;
private boolean mOpaque = true;
- private boolean mVisible = false;
+ private boolean mAppForcedInvisible = false;
+ private AppWindowToken mAppToken;
+ public boolean mVisible = false;
+ public int mLayer = -1;
public SurfaceControlWithBackground(SurfaceSession s,
- String name, int w, int h, int format, int flags)
+ String name, int w, int h, int format, int flags,
+ AppWindowToken token)
throws OutOfResourcesException {
super(s, name, w, h, format, flags);
mBackgroundControl = new SurfaceControl(s, name, w, h,
PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
+ mAppToken = token;
+
+ mAppToken.addSurfaceViewBackground(this);
}
@Override
@@ -782,6 +790,10 @@ class WindowSurfaceController {
public void setLayer(int zorder) {
super.setLayer(zorder);
mBackgroundControl.setLayer(zorder - 1);
+ if (mLayer != zorder) {
+ mLayer = zorder;
+ mAppToken.updateSurfaceViewBackgroundVisibilities();
+ }
}
@Override
@@ -818,7 +830,7 @@ class WindowSurfaceController {
public void setOpaque(boolean isOpaque) {
super.setOpaque(isOpaque);
mOpaque = isOpaque;
- updateBackgroundVisibility();
+ updateBackgroundVisibility(mAppForcedInvisible);
}
@Override
@@ -834,23 +846,28 @@ class WindowSurfaceController {
@Override
public void hide() {
- mVisible = false;
super.hide();
- updateBackgroundVisibility();
+ if (mVisible) {
+ mVisible = false;
+ mAppToken.updateSurfaceViewBackgroundVisibilities();
+ }
}
@Override
public void show() {
- mVisible = true;
super.show();
- updateBackgroundVisibility();
+ if (!mVisible) {
+ mVisible = true;
+ mAppToken.updateSurfaceViewBackgroundVisibilities();
+ }
}
@Override
public void destroy() {
super.destroy();
mBackgroundControl.destroy();
- }
+ mAppToken.removeSurfaceViewBackground(this);
+ }
@Override
public void release() {
@@ -870,8 +887,9 @@ class WindowSurfaceController {
mBackgroundControl.deferTransactionUntil(handle, frame);
}
- private void updateBackgroundVisibility() {
- if (mOpaque && mVisible) {
+ void updateBackgroundVisibility(boolean forcedInvisible) {
+ mAppForcedInvisible = forcedInvisible;
+ if (mOpaque && mVisible && !mAppForcedInvisible) {
mBackgroundControl.show();
} else {
mBackgroundControl.hide();
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 359063c80dbf..e5f972886ccf 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -1074,6 +1074,8 @@ class WindowSurfacePlacer {
if (!transitionGoodToGo(appsCount)) {
return 0;
}
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
+
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
int transit = mService.mAppTransition.getAppTransition();
if (mService.mSkipAppTransitionAnimation) {
@@ -1207,6 +1209,9 @@ class WindowSurfacePlacer {
true /*updateInputWindows*/);
mService.mFocusMayChange = false;
mService.notifyActivityDrawnForKeyguard();
+
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+
return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b5280165bb39..c42d4617b179 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8193,6 +8193,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public SystemUpdatePolicy getSystemUpdatePolicy() {
+ if (UserManager.isDeviceInDemoMode(mContext)) {
+ // Pretending to have an automatic update policy when the device is in retail demo
+ // mode. This will allow the device to download and install an ota without
+ // any user interaction.
+ return SystemUpdatePolicy.createAutomaticInstallPolicy();
+ }
synchronized (this) {
SystemUpdatePolicy policy = mOwners.getSystemUpdatePolicy();
if (policy != null && !policy.isValid()) {
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 96c852bf55f5..5852626db83b 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -30,6 +30,7 @@ import android.net.DhcpResults;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.NetworkUtils;
+import android.net.metrics.IpConnectivityLog;
import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent;
import android.os.Message;
@@ -163,6 +164,7 @@ public class DhcpClient extends StateMachine {
// System services / libraries we use.
private final Context mContext;
private final Random mRandom;
+ private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
// Sockets.
// - We use a packet socket to receive, because servers send us packets bound for IP addresses
@@ -356,14 +358,14 @@ public class DhcpClient extends StateMachine {
} catch (IOException|ErrnoException e) {
if (!mStopped) {
Log.e(TAG, "Read error", e);
- DhcpErrorEvent.logReceiveError(mIfaceName);
+ logError(DhcpErrorEvent.RECEIVE_ERROR);
}
} catch (DhcpPacket.ParseException e) {
Log.e(TAG, "Can't parse packet: " + e.getMessage());
if (PACKET_DBG) {
Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
}
- DhcpErrorEvent.logParseError(mIfaceName, e.errorCode);
+ logError(e.errorCode);
}
}
if (DBG) Log.d(TAG, "Receive thread stopped");
@@ -493,7 +495,7 @@ public class DhcpClient extends StateMachine {
@Override
public void enter() {
if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
- DhcpClientEvent.logStateEvent(mIfaceName, getName());
+ mMetricsLog.log(new DhcpClientEvent(mIfaceName, getName()));
}
private String messageName(int what) {
@@ -977,4 +979,8 @@ public class DhcpClient extends StateMachine {
class DhcpRebootingState extends LoggingState {
}
+
+ private void logError(int errorCode) {
+ mMetricsLog.log(new DhcpErrorEvent(mIfaceName, errorCode));
+ }
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index cece6c8c0cac..86e15182165d 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -31,6 +31,7 @@ import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.dhcp.DhcpClient;
+import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
import android.os.INetworkManagementService;
import android.os.Message;
@@ -393,6 +394,7 @@ public class IpManager extends StateMachine {
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
private final LocalLog mLocalLog;
+ private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
private NetworkInterface mNetworkInterface;
@@ -634,8 +636,8 @@ public class IpManager extends StateMachine {
private void recordMetric(final int type) {
if (mStartTimeMillis <= 0) { Log.wtf(mTag, "Start time undefined!"); }
- IpManagerEvent.logEvent(type, mInterfaceName,
- SystemClock.elapsedRealtime() - mStartTimeMillis);
+ final long duration = SystemClock.elapsedRealtime() - mStartTimeMillis;
+ mMetricsLog.log(new IpManagerEvent(mInterfaceName, type, duration));
}
// For now: use WifiStateMachine's historical notion of provisioned.
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 27600a768896..afb644f3546b 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -24,6 +24,7 @@ import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpReachabilityEvent;
import android.net.netlink.NetlinkConstants;
import android.net.netlink.NetlinkErrorMessage;
@@ -151,6 +152,7 @@ public class IpReachabilityMonitor {
private final Callback mCallback;
private final NetlinkSocketObserver mNetlinkSocketObserver;
private final Thread mObserverThread;
+ private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@GuardedBy("mLock")
private LinkProperties mLinkProperties = new LinkProperties();
// TODO: consider a map to a private NeighborState class holding more
@@ -359,7 +361,6 @@ public class IpReachabilityMonitor {
}
if (delta == ProvisioningChange.LOST_PROVISIONING) {
- IpReachabilityEvent.logProvisioningLost(mInterfaceName);
final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
Log.w(TAG, logMsg);
if (mCallback != null) {
@@ -367,8 +368,9 @@ public class IpReachabilityMonitor {
// an InetAddress argument.
mCallback.notifyLost(ip, logMsg);
}
+ logEvent(IpReachabilityEvent.PROVISIONING_LOST, 0);
} else {
- IpReachabilityEvent.logNudFailed(mInterfaceName);
+ logEvent(IpReachabilityEvent.NUD_FAILED, 0);
}
}
@@ -393,7 +395,7 @@ public class IpReachabilityMonitor {
break;
}
final int returnValue = probeNeighbor(mInterfaceIndex, target);
- IpReachabilityEvent.logProbeEvent(mInterfaceName, returnValue);
+ logEvent(IpReachabilityEvent.PROBE, returnValue);
}
}
@@ -413,6 +415,11 @@ public class IpReachabilityMonitor {
return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
}
+ private void logEvent(int probeType, int errorCode) {
+ int eventType = probeType | (errorCode & 0xff );
+ mMetricsLog.log(new IpReachabilityEvent(mInterfaceName, eventType));
+ }
+
// TODO: simplify the number of objects by making this extend Thread.
private final class NetlinkSocketObserver implements Runnable {
private NetlinkSocket mSocket;
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 51b1e38237a1..d858e822cdbe 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -106,7 +106,7 @@ public class RetailDemoModeService extends SystemService {
private PendingIntent mResetDemoPendingIntent;
private CameraManager mCameraManager;
private String[] mCameraIdsWithFlash;
- private Configuration mPrimaryUserConfiguration;
+ private Configuration mSystemUserConfiguration;
final Object mActivityLock = new Object();
// Whether the newly created demo user has interacted with the screen yet
@@ -179,8 +179,8 @@ public class RetailDemoModeService extends SystemService {
private void showInactivityCountdownDialog() {
UserInactivityCountdownDialog dialog = new UserInactivityCountdownDialog(getContext(),
WARNING_DIALOG_TIMEOUT, MILLIS_PER_SECOND);
- dialog.setPositiveButtonClickListener(null);
- dialog.setNegativeButtonClickListener(new DialogInterface.OnClickListener() {
+ dialog.setNegativeButtonClickListener(null);
+ dialog.setPositiveButtonClickListener(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
@@ -366,12 +366,12 @@ public class RetailDemoModeService extends SystemService {
}
}
- private Configuration getPrimaryUsersConfiguration() {
- if (mPrimaryUserConfiguration == null) {
+ private Configuration getSystemUsersConfiguration() {
+ if (mSystemUserConfiguration == null) {
Settings.System.getConfiguration(getContext().getContentResolver(),
- mPrimaryUserConfiguration = new Configuration());
+ mSystemUserConfiguration = new Configuration());
}
- return mPrimaryUserConfiguration;
+ return mSystemUserConfiguration;
}
@Override
@@ -424,10 +424,11 @@ public class RetailDemoModeService extends SystemService {
mWakeLock.acquire();
}
mCurrentUserId = userId;
- mNm.notifyAsUser(TAG, 1, createResetNotification(), UserHandle.of(userId));
+ mAmi.updatePersistentConfigurationForUser(getSystemUsersConfiguration(), userId);
turnOffAllFlashLights();
muteVolumeStreams();
- mAmi.updatePersistentConfigurationForUser(getPrimaryUsersConfiguration(), userId);
+ mNm.notifyAsUser(TAG, 1, createResetNotification(), UserHandle.of(userId));
+
synchronized (mActivityLock) {
mUserUntouched = true;
}
diff --git a/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java b/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java
index e6548b79f9a1..d14f4eb33dc5 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java
@@ -20,8 +20,6 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.CountDownTimer;
-import android.view.LayoutInflater;
-import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
@@ -30,25 +28,23 @@ import com.android.internal.R;
public class UserInactivityCountdownDialog extends AlertDialog {
private OnCountDownExpiredListener mOnCountDownExpiredListener;
- private View mDialogView;
private CountDownTimer mCountDownTimer;
private long mCountDownDuration;
private long mRefreshInterval;
UserInactivityCountdownDialog(Context context, long duration, long refreshInterval) {
super(context);
-
mCountDownDuration = duration;
mRefreshInterval = refreshInterval;
- mDialogView = LayoutInflater.from(context).inflate(R.layout.alert_dialog, null);
- String msg = context.getString(R.string.demo_user_inactivity_timeout_countdown, duration);
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
getWindow().setAttributes(attrs);
+
setTitle(R.string.demo_user_inactivity_timeout_title);
- setView(mDialogView);
- setMessage(msg);
+ setMessage(getContext().getString(R.string.demo_user_inactivity_timeout_countdown,
+ duration));
}
public void setOnCountDownExpiredListener(
@@ -58,30 +54,31 @@ public class UserInactivityCountdownDialog extends AlertDialog {
public void setPositiveButtonClickListener(OnClickListener onClickListener) {
setButton(Dialog.BUTTON_POSITIVE,
- getContext().getString(R.string.demo_user_inactivity_timeout_left_button),
+ getContext().getString(R.string.demo_user_inactivity_timeout_right_button),
onClickListener);
}
public void setNegativeButtonClickListener(OnClickListener onClickListener) {
setButton(Dialog.BUTTON_NEGATIVE,
- getContext().getString(R.string.demo_user_inactivity_timeout_right_button),
+ getContext().getString(R.string.demo_user_inactivity_timeout_left_button),
onClickListener);
}
@Override
public void show() {
super.show();
- mDialogView.post(new Runnable() {
+ final TextView messageView = (TextView) findViewById(R.id.message);
+ messageView.post(new Runnable() {
@Override
public void run() {
mCountDownTimer = new CountDownTimer(mCountDownDuration, mRefreshInterval) {
@Override
public void onTick(long millisUntilFinished) {
- String msg = getContext().getResources().getString(
+ String msg = getContext().getString(
R.string.demo_user_inactivity_timeout_countdown,
millisUntilFinished / 1000);
- ((TextView) mDialogView.findViewById(R.id.message)).setText(msg);
+ messageView.setText(msg);
}
@Override
@@ -96,8 +93,7 @@ public class UserInactivityCountdownDialog extends AlertDialog {
}
@Override
- public void dismiss() {
- super.dismiss();
+ public void onStop() {
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
}
diff --git a/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java b/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
new file mode 100644
index 000000000000..1433f959898c
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.net.ConnectivityMetricsEvent;
+import android.net.IConnectivityMetricsLogger;
+
+import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+public class IpConnectivityLogTest extends TestCase {
+
+ // use same Parcel object everywhere for pointer equality
+ static final Bundle FAKE_EV = new Bundle();
+
+ @Mock IConnectivityMetricsLogger mService;
+ ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
+
+ IpConnectivityLog mLog;
+
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
+ mLog = new IpConnectivityLog(mService);
+ }
+
+ public void testLogEvents() throws Exception {
+ assertTrue(mLog.log(1, FAKE_EV));
+ assertTrue(mLog.log(2, FAKE_EV));
+ assertTrue(mLog.log(3, FAKE_EV));
+
+ List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
+ assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+ assertEventsEqual(expectedEvent(2), gotEvents.get(1));
+ assertEventsEqual(expectedEvent(3), gotEvents.get(2));
+ }
+
+ public void testLogEventTriggerThrottling() throws Exception {
+ when(mService.logEvent(any())).thenReturn(1234L);
+
+ assertFalse(mLog.log(1, FAKE_EV));
+ }
+
+ public void testLogEventFails() throws Exception {
+ when(mService.logEvent(any())).thenReturn(-1L); // Error.
+
+ assertFalse(mLog.log(1, FAKE_EV));
+ }
+
+ public void testLogEventWhenThrottling() throws Exception {
+ when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
+
+ // No events are logged. The service is only called once
+ // After that, throttling state is maintained locally.
+ assertFalse(mLog.log(1, FAKE_EV));
+ assertFalse(mLog.log(2, FAKE_EV));
+
+ List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
+ assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+ }
+
+ public void testLogEventRecoverFromThrottling() throws Exception {
+ final long throttleTimeout = System.currentTimeMillis() + 50;
+ when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
+
+ assertFalse(mLog.log(1, FAKE_EV));
+ new Thread() {
+ public void run() {
+ busySpinLog();
+ }
+ }.start();
+
+ List<ConnectivityMetricsEvent> gotEvents = verifyEvents(2, 200);
+ assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+ assertEventsEqual(expectedEvent(2), gotEvents.get(1));
+ }
+
+ public void testLogEventRecoverFromThrottlingWithMultipleCallers() throws Exception {
+ final long throttleTimeout = System.currentTimeMillis() + 50;
+ when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
+
+ assertFalse(mLog.log(1, FAKE_EV));
+ final int nCallers = 10;
+ for (int i = 0; i < nCallers; i++) {
+ new Thread() {
+ public void run() {
+ busySpinLog();
+ }
+ }.start();
+ }
+
+ List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1 + nCallers, 200);
+ assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+ for (int i = 0; i < nCallers; i++) {
+ assertEventsEqual(expectedEvent(2), gotEvents.get(1 + i));
+ }
+ }
+
+ void busySpinLog() {
+ final long timeout = 200;
+ final long stop = System.currentTimeMillis() + timeout;
+ try {
+ while (System.currentTimeMillis() < stop) {
+ if (mLog.log(2, FAKE_EV)) {
+ return;
+ }
+ Thread.sleep(10);
+ }
+ } catch (InterruptedException e) { }
+ }
+
+ List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
+ verify(mService, times(n)).logEvent(evCaptor.capture());
+ return evCaptor.getAllValues();
+ }
+
+ List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
+ verify(mService, timeout(timeoutMs).times(n)).logEvent(evCaptor.capture());
+ return evCaptor.getAllValues();
+ }
+
+ static ConnectivityMetricsEvent expectedEvent(int timestamp) {
+ return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
+ }
+
+ /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
+ static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
+ assertEquals(expected.timestamp, got.timestamp);
+ assertEquals(expected.componentTag, got.componentTag);
+ assertEquals(expected.eventTag, got.eventTag);
+ assertEquals(expected.data, got.data);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
new file mode 100644
index 000000000000..033b2c96c8f5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016, 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.connectivity;
+
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.metrics.DnsEvent;
+import android.net.metrics.IDnsEventListener;
+import android.net.metrics.IpConnectivityLog;
+
+import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.IntStream;
+
+public class DnsEventListenerServiceTest extends TestCase {
+
+ // TODO: read from DnsEventListenerService after this constant is read from system property
+ static final int BATCH_SIZE = 100;
+ static final int EVENT_TYPE = IDnsEventListener.EVENT_GETADDRINFO;
+ // TODO: read from IDnsEventListener
+ static final int RETURN_CODE = 1;
+
+ static final byte[] EVENT_TYPES = new byte[BATCH_SIZE];
+ static final byte[] RETURN_CODES = new byte[BATCH_SIZE];
+ static final int[] LATENCIES = new int[BATCH_SIZE];
+ static {
+ for (int i = 0; i < BATCH_SIZE; i++) {
+ EVENT_TYPES[i] = EVENT_TYPE;
+ RETURN_CODES[i] = RETURN_CODE;
+ LATENCIES[i] = i;
+ }
+ }
+
+ DnsEventListenerService mDnsService;
+
+ @Mock ConnectivityManager mCm;
+ @Mock IpConnectivityLog mLog;
+ ArgumentCaptor<NetworkCallback> mCallbackCaptor;
+ ArgumentCaptor<DnsEvent> mEvCaptor;
+
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
+ mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
+ mDnsService = new DnsEventListenerService(mCm, mLog);
+
+ verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
+ }
+
+ public void testOneBatch() throws Exception {
+ log(105, LATENCIES);
+ log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
+
+ verifyLoggedEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
+
+ log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
+
+ mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
+ verifyLoggedEvents(
+ new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+ new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
+ }
+
+ public void testSeveralBatches() throws Exception {
+ log(105, LATENCIES);
+ log(106, LATENCIES);
+ log(105, LATENCIES);
+ log(107, LATENCIES);
+
+ verifyLoggedEvents(
+ new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+ new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
+ new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+ new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
+ }
+
+ public void testBatchAndNetworkLost() throws Exception {
+ byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
+ byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
+ int[] latencies = Arrays.copyOf(LATENCIES, 20);
+
+ log(105, LATENCIES);
+ log(105, latencies);
+ mCallbackCaptor.getValue().onLost(new Network(105));
+ log(105, LATENCIES);
+
+ verifyLoggedEvents(
+ new DnsEvent(105, eventTypes, returnCodes, latencies),
+ new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+ new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
+ }
+
+ public void testConcurrentBatchesAndDumps() throws Exception {
+ final long stop = System.currentTimeMillis() + 100;
+ final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
+ new Thread() {
+ public void run() {
+ while (System.currentTimeMillis() < stop) {
+ mDnsService.dump(pw);
+ }
+ }
+ }.start();
+
+ logAsync(105, LATENCIES);
+ logAsync(106, LATENCIES);
+ logAsync(107, LATENCIES);
+
+ verifyLoggedEvents(500,
+ new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+ new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
+ new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
+ }
+
+ public void testConcurrentBatchesAndNetworkLoss() throws Exception {
+ logAsync(105, LATENCIES);
+ Thread.sleep(10L);
+ // call onLost() asynchronously to logAsync's onDnsEvent() calls.
+ mCallbackCaptor.getValue().onLost(new Network(105));
+
+ // do not verify unpredictable batch
+ verify(mLog, timeout(500).times(1)).log(any());
+ }
+
+ void log(int netId, int[] latencies) {
+ for (int l : latencies) {
+ mDnsService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
+ }
+ }
+
+ void logAsync(int netId, int[] latencies) {
+ new Thread() {
+ public void run() {
+ log(netId, latencies);
+ }
+ }.start();
+ }
+
+ void verifyLoggedEvents(DnsEvent... expected) {
+ verifyLoggedEvents(0, expected);
+ }
+
+ void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
+ verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
+ for (DnsEvent got : mEvCaptor.getAllValues()) {
+ OptionalInt index = IntStream.range(0, expectedEvents.length)
+ .filter(i -> eventsEqual(expectedEvents[i], got))
+ .findFirst();
+ // Don't match same expected event more than once.
+ index.ifPresent(i -> expectedEvents[i] = null);
+ assertTrue(index.isPresent());
+ }
+ }
+
+ /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
+ static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
+ return (expected == got) || ((expected != null) && (got != null)
+ && (expected.netId == got.netId)
+ && Arrays.equals(expected.eventTypes, got.eventTypes)
+ && Arrays.equals(expected.returnCodes, got.returnCodes)
+ && Arrays.equals(expected.latenciesMs, got.latenciesMs));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
new file mode 100644
index 000000000000..5f84ea1bfd96
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2016, 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.connectivity;
+
+import android.content.Context;
+import android.net.ConnectivityMetricsEvent;
+import android.os.Bundle;
+import android.os.RemoteException;
+import static android.net.ConnectivityMetricsEvent.Reference;
+
+import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertArrayEquals;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/*
+ * TODO:
+ * - allow overriding MetricsLoggerService constants in tests.
+ * - test intents are correctly sent after the notification threshold.
+ * - test oldest events are correctly pushed out when internal deque is full.
+ * - test throttling triggers correctly.
+ */
+public class MetricsLoggerServiceTest extends TestCase {
+
+ static final int COMPONENT_TAG = 1;
+ static final long N_EVENTS = 10L;
+ static final ConnectivityMetricsEvent EVENTS[] = new ConnectivityMetricsEvent[(int)N_EVENTS];
+ static {
+ for (int i = 0; i < N_EVENTS; i++) {
+ EVENTS[i] = new ConnectivityMetricsEvent(i, COMPONENT_TAG, i, new Bundle());
+ }
+ }
+
+ static final ConnectivityMetricsEvent NO_EVENTS[] = new ConnectivityMetricsEvent[0];
+
+ @Mock Context mContext;
+ MetricsLoggerService mService;
+
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mService = new MetricsLoggerService(mContext);
+ mService.onStart();
+ }
+
+ public void testGetNoEvents() throws Exception {
+ Reference r = new Reference(0);
+ assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
+ assertEquals(0, r.getValue());
+ }
+
+ public void testLogAndGetEvents() throws Exception {
+ mService.mBinder.logEvents(EVENTS);
+
+ Reference r = new Reference(0);
+
+ assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
+ assertEquals(N_EVENTS, r.getValue());
+
+ assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
+ assertEquals(N_EVENTS, r.getValue());
+ }
+
+ public void testLogOneByOne() throws Exception {
+ for (ConnectivityMetricsEvent ev : EVENTS) {
+ mService.mBinder.logEvent(ev);
+ }
+
+ Reference r = new Reference(0);
+
+ assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
+ assertEquals(N_EVENTS, r.getValue());
+
+ assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
+ assertEquals(N_EVENTS, r.getValue());
+ }
+
+ public void testInterleavedLogAndGet() throws Exception {
+ mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
+
+ Reference r = new Reference(0);
+
+ assertArrayEquals(Arrays.copyOfRange(EVENTS, 0, 3), mService.mBinder.getEvents(r));
+ assertEquals(3, r.getValue());
+
+ mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 8));
+ mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 8, 10));
+
+ assertArrayEquals(Arrays.copyOfRange(EVENTS, 3, 10), mService.mBinder.getEvents(r));
+ assertEquals(N_EVENTS, r.getValue());
+
+ assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
+ assertEquals(N_EVENTS, r.getValue());
+ }
+
+ public void testMultipleGetAll() throws Exception {
+ mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
+
+ Reference r1 = new Reference(0);
+ assertArrayEquals(Arrays.copyOf(EVENTS, 3), mService.mBinder.getEvents(r1));
+ assertEquals(3, r1.getValue());
+
+ mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 10));
+
+ Reference r2 = new Reference(0);
+ assertArrayEquals(EVENTS, mService.mBinder.getEvents(r2));
+ assertEquals(N_EVENTS, r2.getValue());
+ }
+
+ public void testLogAndDumpConcurrently() throws Exception {
+ for (int i = 0; i < 50; i++) {
+ mContext = null;
+ mService = null;
+ setUp();
+ logAndDumpConcurrently();
+ }
+ }
+
+ public void logAndDumpConcurrently() throws Exception {
+ final CountDownLatch latch = new CountDownLatch((int)N_EVENTS);
+ final FileDescriptor fd = new FileOutputStream("/dev/null").getFD();
+
+ for (ConnectivityMetricsEvent ev : EVENTS) {
+ new Thread() {
+ public void run() {
+ mService.mBinder.logEvent(ev);
+ latch.countDown();
+ }
+ }.start();
+ }
+
+ new Thread() {
+ public void run() {
+ while (latch.getCount() > 0) {
+ mService.mBinder.dump(fd, new String[]{"--all"});
+ }
+ }
+ }.start();
+
+ latch.await(100, TimeUnit.MILLISECONDS);
+
+ Reference r = new Reference(0);
+ ConnectivityMetricsEvent[] got = mService.mBinder.getEvents(r);
+ Arrays.sort(got, new EventComparator());
+ assertArrayEquals(EVENTS, got);
+ assertEquals(N_EVENTS, r.getValue());
+ }
+
+ static class EventComparator implements Comparator<ConnectivityMetricsEvent> {
+ public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
+ return Long.compare(ev1.timestamp, ev2.timestamp);
+ }
+ public boolean equal(Object o) {
+ return o instanceof EventComparator;
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1cd32b6bff0f..bbc3d2fd5927 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -561,6 +561,12 @@ public class WifiManager {
public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
/**
+ * Internally used Wi-Fi lock mode representing the case were no locks are held.
+ * @hide
+ */
+ public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
+
+ /**
* In this Wi-Fi lock mode, Wi-Fi will be kept active,
* and will behave normally, i.e., it will attempt to automatically
* establish a connection to a remembered access point that is