Merge changes Id931d441,I83faf974
* changes:
Zygote: Improve logging and error handling during connections.
Zygote: Fix race condition on package preloads.
diff --git a/Android.mk b/Android.mk
index bd32b55..28e53c6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -487,7 +487,7 @@
telecomm/java/com/android/internal/telecom/ITelecomService.aidl \
telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl \
telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl \
- telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl \
+ telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl \
telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl \
telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl \
telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6e4890c..093f8b0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -39779,13 +39779,12 @@
field public static final int STATUS_UNKNOWN = 0; // 0x0
}
- public class MbmsStreamingManager {
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int, android.os.Handler) throws android.telephony.mbms.MbmsException;
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback) throws android.telephony.mbms.MbmsException;
- method public void dispose();
- method public void getStreamingServices(java.util.List<java.lang.String>) throws android.telephony.mbms.MbmsException;
- method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
+ public class MbmsStreamingSession implements java.lang.AutoCloseable {
+ method public void close();
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, int, android.os.Handler);
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, android.os.Handler);
+ method public void requestUpdateStreamingServices(java.util.List<java.lang.String>);
+ method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler);
}
public class NeighboringCellInfo implements android.os.Parcelable {
@@ -40510,27 +40509,26 @@
field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
}
- public class MbmsStreamingManagerCallback {
- ctor public MbmsStreamingManagerCallback();
+ public class MbmsStreamingSessionCallback {
+ ctor public MbmsStreamingSessionCallback();
method public void onError(int, java.lang.String);
method public void onMiddlewareReady();
method public void onStreamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>);
}
public class ServiceInfo {
- method public java.lang.String getClassName();
method public java.util.List<java.util.Locale> getLocales();
method public java.util.Map<java.util.Locale, java.lang.String> getNames();
+ method public java.lang.String getServiceClassName();
method public java.lang.String getServiceId();
method public java.util.Date getSessionEndTime();
method public java.util.Date getSessionStartTime();
}
public class StreamingService {
- method public void dispose() throws android.telephony.mbms.MbmsException;
method public android.telephony.mbms.StreamingServiceInfo getInfo();
- method public android.net.Uri getPlaybackUri() throws android.telephony.mbms.MbmsException;
- method public void stopStreaming() throws android.telephony.mbms.MbmsException;
+ method public android.net.Uri getPlaybackUri();
+ method public void stopStreaming();
field public static final int BROADCAST_METHOD = 1; // 0x1
field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
field public static final int REASON_END_OF_SESSION = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index 5a57171..383a465 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -43209,13 +43209,12 @@
field public static final int STATUS_UNKNOWN = 0; // 0x0
}
- public class MbmsStreamingManager {
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int, android.os.Handler) throws android.telephony.mbms.MbmsException;
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback) throws android.telephony.mbms.MbmsException;
- method public void dispose();
- method public void getStreamingServices(java.util.List<java.lang.String>) throws android.telephony.mbms.MbmsException;
- method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
+ public class MbmsStreamingSession implements java.lang.AutoCloseable {
+ method public void close();
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, int, android.os.Handler);
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, android.os.Handler);
+ method public void requestUpdateStreamingServices(java.util.List<java.lang.String>);
+ method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler);
field public static final java.lang.String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
@@ -44035,27 +44034,26 @@
field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
}
- public class MbmsStreamingManagerCallback {
- ctor public MbmsStreamingManagerCallback();
+ public class MbmsStreamingSessionCallback {
+ ctor public MbmsStreamingSessionCallback();
method public void onError(int, java.lang.String);
method public void onMiddlewareReady();
method public void onStreamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>);
}
public class ServiceInfo {
- method public java.lang.String getClassName();
method public java.util.List<java.util.Locale> getLocales();
method public java.util.Map<java.util.Locale, java.lang.String> getNames();
+ method public java.lang.String getServiceClassName();
method public java.lang.String getServiceId();
method public java.util.Date getSessionEndTime();
method public java.util.Date getSessionStartTime();
}
public class StreamingService {
- method public void dispose() throws android.telephony.mbms.MbmsException;
method public android.telephony.mbms.StreamingServiceInfo getInfo();
- method public android.net.Uri getPlaybackUri() throws android.telephony.mbms.MbmsException;
- method public void stopStreaming() throws android.telephony.mbms.MbmsException;
+ method public android.net.Uri getPlaybackUri();
+ method public void stopStreaming();
field public static final int BROADCAST_METHOD = 1; // 0x1
field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
field public static final int REASON_END_OF_SESSION = 2; // 0x2
@@ -44116,11 +44114,10 @@
public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public void dispose(int) throws android.os.RemoteException;
- method public void disposeStream(int, java.lang.String) throws android.os.RemoteException;
method public android.net.Uri getPlaybackUri(int, java.lang.String) throws android.os.RemoteException;
- method public int getStreamingServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
- method public int initialize(android.telephony.mbms.MbmsStreamingManagerCallback, int) throws android.os.RemoteException;
+ method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException;
method public void onAppCallbackDied(int, int);
+ method public int requestUpdateStreamingServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
method public int startStreaming(int, java.lang.String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException;
method public void stopStreaming(int, java.lang.String) throws android.os.RemoteException;
}
diff --git a/api/test-current.txt b/api/test-current.txt
index b51a2b7..a50b01d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -40001,13 +40001,12 @@
field public static final int STATUS_UNKNOWN = 0; // 0x0
}
- public class MbmsStreamingManager {
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int, android.os.Handler) throws android.telephony.mbms.MbmsException;
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
- method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback) throws android.telephony.mbms.MbmsException;
- method public void dispose();
- method public void getStreamingServices(java.util.List<java.lang.String>) throws android.telephony.mbms.MbmsException;
- method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
+ public class MbmsStreamingSession implements java.lang.AutoCloseable {
+ method public void close();
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, int, android.os.Handler);
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, android.os.Handler);
+ method public void requestUpdateStreamingServices(java.util.List<java.lang.String>);
+ method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler);
}
public class NeighboringCellInfo implements android.os.Parcelable {
@@ -40732,27 +40731,26 @@
field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
}
- public class MbmsStreamingManagerCallback {
- ctor public MbmsStreamingManagerCallback();
+ public class MbmsStreamingSessionCallback {
+ ctor public MbmsStreamingSessionCallback();
method public void onError(int, java.lang.String);
method public void onMiddlewareReady();
method public void onStreamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>);
}
public class ServiceInfo {
- method public java.lang.String getClassName();
method public java.util.List<java.util.Locale> getLocales();
method public java.util.Map<java.util.Locale, java.lang.String> getNames();
+ method public java.lang.String getServiceClassName();
method public java.lang.String getServiceId();
method public java.util.Date getSessionEndTime();
method public java.util.Date getSessionStartTime();
}
public class StreamingService {
- method public void dispose() throws android.telephony.mbms.MbmsException;
method public android.telephony.mbms.StreamingServiceInfo getInfo();
- method public android.net.Uri getPlaybackUri() throws android.telephony.mbms.MbmsException;
- method public void stopStreaming() throws android.telephony.mbms.MbmsException;
+ method public android.net.Uri getPlaybackUri();
+ method public void stopStreaming();
field public static final int BROADCAST_METHOD = 1; // 0x1
field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
field public static final int REASON_END_OF_SESSION = 2; // 0x2
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 83a82f7..a2af342 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -311,8 +311,7 @@
for (BluetoothGattService brokenRef : includedServices) {
BluetoothGattService includedService = getService(mDevice,
- brokenRef.getUuid(), brokenRef.getInstanceId(),
- brokenRef.getType());
+ brokenRef.getUuid(), brokenRef.getInstanceId());
if (includedService != null) {
fixedService.addIncludedService(includedService);
} else {
@@ -714,10 +713,9 @@
* @hide
*/
/*package*/ BluetoothGattService getService(BluetoothDevice device, UUID uuid,
- int instanceId, int type) {
+ int instanceId) {
for (BluetoothGattService svc : mServices) {
if (svc.getDevice().equals(device)
- && svc.getType() == type
&& svc.getInstanceId() == instanceId
&& svc.getUuid().equals(uuid)) {
return svc;
@@ -913,7 +911,7 @@
/**
* Set the preferred connection PHY for this app. Please note that this is just a
- * recommendation, whether the PHY change will happen depends on other applications peferences,
+ * recommendation, whether the PHY change will happen depends on other applications preferences,
* local and remote controller capabilities. Controller can override these settings.
* <p>
* {@link BluetoothGattCallback#onPhyUpdate} will be triggered as a result of this call, even
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
index 22eba35..2c8114b 100644
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java
@@ -184,7 +184,7 @@
/**
* Callback indicating the connection parameters were updated.
*
- * @param gatt The remote device involved
+ * @param device The remote device involved
* @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from
* 6 (7.5ms) to 3200 (4000ms).
* @param latency Slave latency for the connection in number of connection events. Valid range
@@ -195,7 +195,7 @@
* successfully
* @hide
*/
- public void onConnectionUpdated(BluetoothDevice gatt, int interval, int latency, int timeout,
+ public void onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout,
int status) {
}
diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java
new file mode 100644
index 0000000..cbf3fc8
--- /dev/null
+++ b/core/java/android/net/metrics/WakeupEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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;
+
+/**
+ * An event logged when NFLOG notifies userspace of a wakeup packet for
+ * watched interfaces.
+ * {@hide}
+ */
+public class WakeupEvent {
+ public String iface;
+ public long timestampMs;
+ public int uid;
+
+ @Override
+ public String toString() {
+ return String.format("WakeupEvent(%tT.%tL, %s, uid: %d)",
+ timestampMs, timestampMs, iface, uid);
+ }
+}
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
new file mode 100644
index 0000000..d520b97
--- /dev/null
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 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.Process;
+import android.os.SystemClock;
+
+/**
+ * An event logged per interface and that aggregates WakeupEvents for that interface.
+ * {@hide}
+ */
+public class WakeupStats {
+
+ private static final int NO_UID = -1;
+
+ public final long creationTimeMs = SystemClock.elapsedRealtime();
+ public final String iface;
+
+ public long totalWakeups = 0;
+ public long rootWakeups = 0;
+ public long systemWakeups = 0;
+ public long nonApplicationWakeups = 0;
+ public long applicationWakeups = 0;
+ public long unroutedWakeups = 0;
+ public long durationSec = 0;
+
+ public WakeupStats(String iface) {
+ this.iface = iface;
+ }
+
+ /** Update durationSec with current time. */
+ public void updateDuration() {
+ durationSec = (SystemClock.elapsedRealtime() - creationTimeMs) / 1000;
+ }
+
+ /** Update wakeup counters for the given WakeupEvent. */
+ public void countEvent(WakeupEvent ev) {
+ totalWakeups++;
+ switch (ev.uid) {
+ case Process.ROOT_UID:
+ rootWakeups++;
+ break;
+ case Process.SYSTEM_UID:
+ systemWakeups++;
+ break;
+ case NO_UID:
+ unroutedWakeups++;
+ break;
+ default:
+ if (ev.uid >= Process.FIRST_APPLICATION_UID) {
+ applicationWakeups++;
+ } else {
+ nonApplicationWakeups++;
+ }
+ break;
+ }
+ }
+
+ @Override
+ public String toString() {
+ updateDuration();
+ return new StringBuilder()
+ .append("WakeupStats(").append(iface)
+ .append(", total: ").append(totalWakeups)
+ .append(", root: ").append(rootWakeups)
+ .append(", system: ").append(systemWakeups)
+ .append(", apps: ").append(applicationWakeups)
+ .append(", non-apps: ").append(nonApplicationWakeups)
+ .append(", unrouted: ").append(unroutedWakeups)
+ .append(", ").append(durationSec).append("s)")
+ .toString();
+ }
+}
diff --git a/proto/src/ipconnectivity.proto b/proto/src/ipconnectivity.proto
index 01fb860..d997a80 100644
--- a/proto/src/ipconnectivity.proto
+++ b/proto/src/ipconnectivity.proto
@@ -473,6 +473,38 @@
repeated Pair validation_states = 8;
}
+// Represents statistics from NFLOG wakeup events due to ingress packets.
+// Since oc-mr1.
+// Next tag: 8.
+message WakeupStats {
+ // The time duration in seconds covered by these stats, for deriving
+ // exact wakeup rates.
+ optional int64 duration_sec = 1;
+
+ // The total number of ingress packets waking up the device.
+ optional int64 total_wakeups = 2;
+
+ // The total number of wakeup packets routed to a socket belonging to
+ // the root uid (uid 0).
+ optional int64 root_wakeups = 3;
+
+ // The total number of wakeup packets routed to a socket belonging to
+ // the system server (uid 1000).
+ optional int64 system_wakeups = 4;
+
+ // The total number of wakeup packets routed to a socket belonging to
+ // an application (uid > 9999).
+ optional int64 application_wakeups = 5;
+
+ // The total number of wakeup packets routed to a socket belonging to another
+ // uid than the root uid, system uid, or an application uid (any uid in
+ // between [1001, 9999]. See android.os.Process for possible uids.
+ optional int64 non_application_wakeups = 6;
+
+ // The total number of wakeup packets with no associated sockets.
+ optional int64 unrouted_wakeups = 7;
+}
+
// Represents one of the IP connectivity event defined in this file.
// Next tag: 20
message IpConnectivityEvent {
@@ -547,6 +579,9 @@
// Network statistics.
NetworkStats network_stats = 19;
+
+ // Ingress packet wakeup statistics.
+ WakeupStats wakeup_stats = 20;
};
};
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index ee38219..22330e6 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -38,6 +38,7 @@
import android.net.metrics.NetworkEvent;
import android.net.metrics.RaEvent;
import android.net.metrics.ValidationProbeEvent;
+import android.net.metrics.WakeupStats;
import android.os.Parcelable;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -115,6 +116,22 @@
return out;
}
+ public static IpConnectivityEvent toProto(WakeupStats in) {
+ IpConnectivityLogClass.WakeupStats wakeupStats =
+ new IpConnectivityLogClass.WakeupStats();
+ in.updateDuration();
+ wakeupStats.durationSec = in.durationSec;
+ wakeupStats.totalWakeups = in.totalWakeups;
+ wakeupStats.rootWakeups = in.rootWakeups;
+ wakeupStats.systemWakeups = in.systemWakeups;
+ wakeupStats.nonApplicationWakeups = in.nonApplicationWakeups;
+ wakeupStats.applicationWakeups = in.applicationWakeups;
+ wakeupStats.unroutedWakeups = in.unroutedWakeups;
+ final IpConnectivityEvent out = buildEvent(0, 0, in.iface);
+ out.setWakeupStats(wakeupStats);
+ return out;
+ }
+
private static IpConnectivityEvent buildEvent(int netId, long transports, String ifname) {
final IpConnectivityEvent ev = new IpConnectivityEvent();
ev.networkId = netId;
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 4094083..6f7ace2 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity;
+import static android.util.TimeUtils.NANOS_PER_MS;
+
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetdEventCallback;
@@ -25,9 +27,12 @@
import android.net.metrics.DnsEvent;
import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.WakeupEvent;
+import android.net.metrics.WakeupStats;
import android.os.RemoteException;
import android.text.format.DateUtils;
import android.util.Log;
+import android.util.ArrayMap;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -59,12 +64,28 @@
private static final int CONNECT_LATENCY_FILL_RATE = 15 * (int) DateUtils.SECOND_IN_MILLIS;
private static final int CONNECT_LATENCY_MAXIMUM_RECORDS = 20000;
+ @VisibleForTesting
+ static final int WAKEUP_EVENT_BUFFER_LENGTH = 1024;
+ // TODO: dedup this String constant with the one used in
+ // ConnectivityService#wakeupModifyInterface().
+ @VisibleForTesting
+ static final String WAKEUP_EVENT_IFACE_PREFIX = "iface:";
+
// Sparse arrays of DNS and connect events, grouped by net id.
@GuardedBy("this")
private final SparseArray<DnsEvent> mDnsEvents = new SparseArray<>();
@GuardedBy("this")
private final SparseArray<ConnectStats> mConnectEvents = new SparseArray<>();
+ // Array of aggregated wakeup event stats, grouped by interface name.
+ @GuardedBy("this")
+ private final ArrayMap<String, WakeupStats> mWakeupStats = new ArrayMap<>();
+ // Ring buffer array for storing packet wake up events sent by Netd.
+ @GuardedBy("this")
+ private final WakeupEvent[] mWakeupEvents = new WakeupEvent[WAKEUP_EVENT_BUFFER_LENGTH];
+ @GuardedBy("this")
+ private long mWakeupEventCursor = 0;
+
private final ConnectivityManager mCm;
@GuardedBy("this")
@@ -137,11 +158,62 @@
@Override
public synchronized void onWakeupEvent(String prefix, int uid, int gid, long timestampNs) {
+ maybeVerboseLog("onWakeupEvent(%s, %d, %d, %sns)", prefix, uid, gid, timestampNs);
+
+ // TODO: add ip protocol and port
+
+ String iface = prefix.replaceFirst(WAKEUP_EVENT_IFACE_PREFIX, "");
+ final long timestampMs;
+ if (timestampNs > 0) {
+ timestampMs = timestampNs / NANOS_PER_MS;
+ } else {
+ timestampMs = System.currentTimeMillis();
+ }
+
+ addWakupEvent(iface, timestampMs, uid);
+ }
+
+ @GuardedBy("this")
+ private void addWakupEvent(String iface, long timestampMs, int uid) {
+ int index = wakeupEventIndex(mWakeupEventCursor);
+ mWakeupEventCursor++;
+ WakeupEvent event = new WakeupEvent();
+ event.iface = iface;
+ event.timestampMs = timestampMs;
+ event.uid = uid;
+ mWakeupEvents[index] = event;
+ WakeupStats stats = mWakeupStats.get(iface);
+ if (stats == null) {
+ stats = new WakeupStats(iface);
+ mWakeupStats.put(iface, stats);
+ }
+ stats.countEvent(event);
+ }
+
+ @GuardedBy("this")
+ private WakeupEvent[] getWakeupEvents() {
+ int length = (int) Math.min(mWakeupEventCursor, (long) mWakeupEvents.length);
+ WakeupEvent[] out = new WakeupEvent[length];
+ // Reverse iteration from youngest event to oldest event.
+ long inCursor = mWakeupEventCursor - 1;
+ int outIdx = out.length - 1;
+ while (outIdx >= 0) {
+ out[outIdx--] = mWakeupEvents[wakeupEventIndex(inCursor--)];
+ }
+ return out;
+ }
+
+ private static int wakeupEventIndex(long cursor) {
+ return (int) Math.abs(cursor % WAKEUP_EVENT_BUFFER_LENGTH);
}
public synchronized void flushStatistics(List<IpConnectivityEvent> events) {
flushProtos(events, mConnectEvents, IpConnectivityEventBuilder::toProto);
flushProtos(events, mDnsEvents, IpConnectivityEventBuilder::toProto);
+ for (int i = 0; i < mWakeupStats.size(); i++) {
+ events.add(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i)));
+ }
+ mWakeupStats.clear();
}
public synchronized void dump(PrintWriter writer) {
@@ -153,13 +225,22 @@
}
public synchronized void list(PrintWriter pw) {
- listEvents(pw, mConnectEvents, (x) -> x);
- listEvents(pw, mDnsEvents, (x) -> x);
+ listEvents(pw, mConnectEvents, (x) -> x, "\n");
+ listEvents(pw, mDnsEvents, (x) -> x, "\n");
+ for (int i = 0; i < mWakeupStats.size(); i++) {
+ pw.println(mWakeupStats.valueAt(i));
+ }
+ for (WakeupEvent wakeup : getWakeupEvents()) {
+ pw.println(wakeup);
+ }
}
public synchronized void listAsProtos(PrintWriter pw) {
- listEvents(pw, mConnectEvents, IpConnectivityEventBuilder::toProto);
- listEvents(pw, mDnsEvents, IpConnectivityEventBuilder::toProto);
+ listEvents(pw, mConnectEvents, IpConnectivityEventBuilder::toProto, "");
+ listEvents(pw, mDnsEvents, IpConnectivityEventBuilder::toProto, "");
+ for (int i = 0; i < mWakeupStats.size(); i++) {
+ pw.print(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i)));
+ }
}
private static <T> void flushProtos(List<IpConnectivityEvent> out, SparseArray<T> in,
@@ -170,10 +251,13 @@
in.clear();
}
- public static <T> void listEvents(
- PrintWriter pw, SparseArray<T> events, Function<T, Object> mapper) {
+ private static <T> void listEvents(
+ PrintWriter pw, SparseArray<T> events, Function<T, Object> mapper, String separator) {
+ // Proto derived Classes have toString method that adds a \n at the end.
+ // Let the caller control that by passing in the line separator explicitly.
for (int i = 0; i < events.size(); i++) {
- pw.println(mapper.apply(events.valueAt(i)).toString());
+ pw.print(mapper.apply(events.valueAt(i)));
+ pw.print(separator);
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index e96f4b0..a4d7242 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -278,6 +278,10 @@
return mHandler;
}
+ public Network network() {
+ return network;
+ }
+
// Functions for manipulating the requests satisfied by this network.
//
// These functions must only called on ConnectivityService's main thread.
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index d3a9354..8b886d6 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -20,7 +20,6 @@
import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
-import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -229,6 +228,8 @@
// Delay between reevaluations once a captive portal has been found.
private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10*60*1000;
+ private static final int NUM_VALIDATION_LOG_LINES = 20;
+
private final Context mContext;
private final Handler mConnectivityServiceHandler;
private final NetworkAgentInfo mNetworkAgentInfo;
@@ -236,9 +237,15 @@
private final int mNetId;
private final TelephonyManager mTelephonyManager;
private final WifiManager mWifiManager;
- private final AlarmManager mAlarmManager;
private final NetworkRequest mDefaultRequest;
private final IpConnectivityLog mMetricsLog;
+ private final NetworkMonitorSettings mSettings;
+
+ // Configuration values for captive portal detection probes.
+ private final String mCaptivePortalUserAgent;
+ private final URL mCaptivePortalHttpsUrl;
+ private final URL mCaptivePortalHttpUrl;
+ private final URL[] mCaptivePortalFallbackUrls;
@VisibleForTesting
protected boolean mIsCaptivePortalCheckEnabled;
@@ -262,40 +269,37 @@
private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null;
- private final LocalLog validationLogs = new LocalLog(20); // 20 lines
+ private final LocalLog validationLogs = new LocalLog(NUM_VALIDATION_LOG_LINES);
private final Stopwatch mEvaluationTimer = new Stopwatch();
// This variable is set before transitioning to the mCaptivePortalState.
private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED;
- // Configuration values for captive portal detection probes.
- private final String mCaptivePortalUserAgent;
- private final URL mCaptivePortalHttpsUrl;
- private final URL mCaptivePortalHttpUrl;
- private final URL[] mCaptivePortalFallbackUrls;
private int mNextFallbackUrlIndex = 0;
public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
NetworkRequest defaultRequest) {
- this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog());
+ this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog(),
+ NetworkMonitorSettings.DEFAULT);
}
@VisibleForTesting
protected NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
- NetworkRequest defaultRequest, IpConnectivityLog logger) {
+ NetworkRequest defaultRequest, IpConnectivityLog logger,
+ NetworkMonitorSettings settings) {
// Add suffix indicating which NetworkMonitor we're talking about.
super(TAG + networkAgentInfo.name());
mContext = context;
mMetricsLog = logger;
mConnectivityServiceHandler = handler;
+ mSettings = settings;
mNetworkAgentInfo = networkAgentInfo;
- mNetwork = new OneAddressPerFamilyNetwork(networkAgentInfo.network);
+ mNetwork = new OneAddressPerFamilyNetwork(networkAgentInfo.network());
mNetId = mNetwork.netId;
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mDefaultRequest = defaultRequest;
addState(mDefaultState);
@@ -305,16 +309,12 @@
addState(mCaptivePortalState, mMaybeNotifyState);
setInitialState(mDefaultState);
- mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_MODE, Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT)
- != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
- mUseHttps = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
-
- mCaptivePortalUserAgent = getCaptivePortalUserAgent(context);
- mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl(context));
- mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl(context));
- mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls(context);
+ mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled();
+ mUseHttps = getUseHttpsValidation();
+ mCaptivePortalUserAgent = getCaptivePortalUserAgent();
+ mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
+ mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl(settings, context));
+ mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
start();
}
@@ -705,19 +705,42 @@
}
}
- private static String getCaptivePortalServerHttpsUrl(Context context) {
- return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
+ public boolean getIsCaptivePortalCheckEnabled() {
+ String symbol = Settings.Global.CAPTIVE_PORTAL_MODE;
+ int defaultValue = Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT;
+ int mode = mSettings.getSetting(mContext, symbol, defaultValue);
+ return mode != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
}
+ public boolean getUseHttpsValidation() {
+ return mSettings.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
+ }
+
+ public boolean getWifiScansAlwaysAvailableDisabled() {
+ return mSettings.getSetting(mContext, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0;
+ }
+
+ private String getCaptivePortalServerHttpsUrl() {
+ return mSettings.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
+ }
+
+ // Static for direct access by ConnectivityService
public static String getCaptivePortalServerHttpUrl(Context context) {
- return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
+ return getCaptivePortalServerHttpUrl(NetworkMonitorSettings.DEFAULT, context);
}
- private URL[] makeCaptivePortalFallbackUrls(Context context) {
+ public static String getCaptivePortalServerHttpUrl(
+ NetworkMonitorSettings settings, Context context) {
+ return settings.getSetting(
+ context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
+ }
+
+ private URL[] makeCaptivePortalFallbackUrls() {
String separator = ",";
- String firstUrl = getSetting(context,
+ String firstUrl = mSettings.getSetting(mContext,
Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
- String joinedUrls = firstUrl + separator + getSetting(context,
+ String joinedUrls = firstUrl + separator + mSettings.getSetting(mContext,
Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, DEFAULT_OTHER_FALLBACK_URLS);
List<URL> urls = new ArrayList<>();
for (String s : joinedUrls.split(separator)) {
@@ -733,13 +756,9 @@
return urls.toArray(new URL[urls.size()]);
}
- private static String getCaptivePortalUserAgent(Context context) {
- return getSetting(context, Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
- }
-
- private static String getSetting(Context context, String symbol, String defaultValue) {
- final String value = Settings.Global.getString(context.getContentResolver(), symbol);
- return value != null ? value : defaultValue;
+ private String getCaptivePortalUserAgent() {
+ return mSettings.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
}
private URL nextFallbackUrl() {
@@ -1035,12 +1054,13 @@
*/
private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
long requestTimestampMs, long responseTimestampMs) {
- if (Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) {
+ if (getWifiScansAlwaysAvailableDisabled()) {
return;
}
- if (systemReady == false) return;
+ if (!systemReady) {
+ return;
+ }
Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
switch (mNetworkAgentInfo.networkInfo.getType()) {
@@ -1144,4 +1164,24 @@
ev.durationMs = durationMs;
mMetricsLog.log(mNetId, transports, ev);
}
+
+ @VisibleForTesting
+ public interface NetworkMonitorSettings {
+ int getSetting(Context context, String symbol, int defaultValue);
+ String getSetting(Context context, String symbol, String defaultValue);
+
+ static NetworkMonitorSettings DEFAULT = new DefaultNetworkMonitorSettings();
+ }
+
+ @VisibleForTesting
+ public static class DefaultNetworkMonitorSettings implements NetworkMonitorSettings {
+ public int getSetting(Context context, String symbol, int defaultValue) {
+ return Settings.Global.getInt(context.getContentResolver(), symbol, defaultValue);
+ }
+
+ public String getSetting(Context context, String symbol, String defaultValue) {
+ final String value = Settings.Global.getString(context.getContentResolver(), symbol);
+ return value != null ? value : defaultValue;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
index 11928b9..6db70cd 100644
--- a/services/core/java/com/android/server/timezone/IntentHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
@@ -53,20 +53,34 @@
// The intent filter that triggers when package update events happen that indicate there may
// be work to do.
IntentFilter packageIntentFilter = new IntentFilter();
- // Either of these mean a downgrade?
- packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+
packageIntentFilter.addDataScheme("package");
packageIntentFilter.addDataSchemeSpecificPart(
updaterAppPackageName, PatternMatcher.PATTERN_LITERAL);
packageIntentFilter.addDataSchemeSpecificPart(
dataAppPackageName, PatternMatcher.PATTERN_LITERAL);
+
+ // ACTION_PACKAGE_ADDED is fired when a package is upgraded or downgraded (in addition to
+ // ACTION_PACKAGE_REMOVED and ACTION_PACKAGE_REPLACED). A system/priv-app can never be
+ // removed entirely so we do not need to trigger on ACTION_PACKAGE_REMOVED or
+ // ACTION_PACKAGE_FULLY_REMOVED.
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+
+ // ACTION_PACKAGE_CHANGED is used when a package is disabled / re-enabled. It is not
+ // strictly necessary to trigger on this but it won't hurt anything and may catch some cases
+ // where a package has changed while disabled.
+ // Note: ACTION_PACKAGE_CHANGED is not fired when updating a suspended app, but
+ // ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and ACTION_PACKAGE_REPLACED are (and the app
+ // is left in an unsuspended state after this).
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+
+ // We do not register for ACTION_PACKAGE_RESTARTED because it doesn't imply an update.
+ // We do not register for ACTION_PACKAGE_DATA_CLEARED because the updater / data apps are
+ // not expected to need local data.
+
Receiver packageUpdateReceiver = new Receiver(listener, true /* packageUpdated */);
mContext.registerReceiver(packageUpdateReceiver, packageIntentFilter);
- // TODO(nfuller): Add more exotic intents as needed. e.g.
- // packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- // Also, disabled...?
mReliabilityReceiver = new Receiver(listener, false /* packageUpdated */);
}
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingSession.java
similarity index 62%
rename from telephony/java/android/telephony/MbmsStreamingManager.java
rename to telephony/java/android/telephony/MbmsStreamingSession.java
index b6b253e..5550ac1 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingSession.java
@@ -16,6 +16,8 @@
package android.telephony;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.content.ComponentName;
@@ -25,18 +27,20 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
-import android.telephony.mbms.InternalStreamingManagerCallback;
+import android.telephony.mbms.InternalStreamingSessionCallback;
import android.telephony.mbms.InternalStreamingServiceCallback;
import android.telephony.mbms.MbmsException;
-import android.telephony.mbms.MbmsStreamingManagerCallback;
+import android.telephony.mbms.MbmsStreamingSessionCallback;
import android.telephony.mbms.MbmsUtils;
import android.telephony.mbms.StreamingService;
import android.telephony.mbms.StreamingServiceCallback;
import android.telephony.mbms.StreamingServiceInfo;
import android.telephony.mbms.vendor.IMbmsStreamingService;
+import android.util.ArraySet;
import android.util.Log;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -45,8 +49,8 @@
/**
* This class provides functionality for streaming media over MBMS.
*/
-public class MbmsStreamingManager {
- private static final String LOG_TAG = "MbmsStreamingManager";
+public class MbmsStreamingSession implements AutoCloseable {
+ private static final String LOG_TAG = "MbmsStreamingSession";
/**
* Service action which must be handled by the middleware implementing the MBMS streaming
@@ -69,94 +73,94 @@
}
};
- private InternalStreamingManagerCallback mInternalCallback;
+ private InternalStreamingSessionCallback mInternalCallback;
+ private Set<StreamingService> mKnownActiveStreamingServices = new ArraySet<>();
private final Context mContext;
private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
/** @hide */
- private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback callback,
+ private MbmsStreamingSession(Context context, MbmsStreamingSessionCallback callback,
int subscriptionId, Handler handler) {
mContext = context;
mSubscriptionId = subscriptionId;
if (handler == null) {
handler = new Handler(Looper.getMainLooper());
}
- mInternalCallback = new InternalStreamingManagerCallback(callback, handler);
+ mInternalCallback = new InternalStreamingSessionCallback(callback, handler);
}
/**
- * Create a new MbmsStreamingManager using the given subscription ID.
+ * Create a new {@link MbmsStreamingSession} using the given subscription ID.
*
* Note that this call will bind a remote service. You may not call this method on your app's
- * main thread. This may throw an {@link MbmsException}, indicating errors that may happen
- * during the initialization or binding process.
+ * main thread.
*
- *
- * You may only have one instance of {@link MbmsStreamingManager} per UID. If you call this
- * method while there is an active instance of {@link MbmsStreamingManager} in your process
- * (in other words, one that has not had {@link #dispose()} called on it), this method will
- * throw an {@link MbmsException}. If you call this method in a different process
+ * You may only have one instance of {@link MbmsStreamingSession} per UID. If you call this
+ * method while there is an active instance of {@link MbmsStreamingSession} in your process
+ * (in other words, one that has not had {@link #close()} called on it), this method will
+ * throw an {@link IllegalStateException}. If you call this method in a different process
* running under the same UID, an error will be indicated via
- * {@link MbmsStreamingManagerCallback#onError(int, String)}.
+ * {@link MbmsStreamingSessionCallback#onError(int, String)}.
*
* Note that initialization may fail asynchronously. If you wish to try again after you
- * receive such an asynchronous error, you must call dispose() on the instance of
- * {@link MbmsStreamingManager} that you received before calling this method again.
+ * receive such an asynchronous error, you must call {@link #close()} on the instance of
+ * {@link MbmsStreamingSession} that you received before calling this method again.
*
* @param context The {@link Context} to use.
* @param callback A callback object on which you wish to receive results of asynchronous
* operations.
* @param subscriptionId The subscription ID to use.
- * @param handler The handler you wish to receive callbacks on. If null, callbacks will be
- * processed on the main looper (in other words, the looper returned from
- * {@link Looper#getMainLooper()}).
+ * @param handler The handler you wish to receive callbacks on.
+ * @return An instance of {@link MbmsStreamingSession}, or null if an error occurred.
*/
- public static MbmsStreamingManager create(Context context,
- MbmsStreamingManagerCallback callback, int subscriptionId, Handler handler)
- throws MbmsException {
+ public static @Nullable MbmsStreamingSession create(@NonNull Context context,
+ @NonNull MbmsStreamingSessionCallback callback, int subscriptionId,
+ @NonNull Handler handler) {
if (!sIsInitialized.compareAndSet(false, true)) {
- throw new MbmsException(MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE);
+ throw new IllegalStateException("Cannot create two instances of MbmsStreamingSession");
}
- MbmsStreamingManager manager = new MbmsStreamingManager(context, callback,
+ MbmsStreamingSession session = new MbmsStreamingSession(context, callback,
subscriptionId, handler);
- try {
- manager.bindAndInitialize();
- } catch (MbmsException e) {
+
+ int result = session.bindAndInitialize();
+ if (result != MbmsException.SUCCESS) {
sIsInitialized.set(false);
- throw e;
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(result, null);
+ }
+ });
+ return null;
}
- return manager;
+ return session;
}
/**
- * Create a new MbmsStreamingManager using the system default data subscription ID.
- * See {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}.
+ * Create a new {@link MbmsStreamingSession} using the system default data subscription ID.
+ * See {@link #create(Context, MbmsStreamingSessionCallback, int, Handler)}.
*/
- public static MbmsStreamingManager create(Context context,
- MbmsStreamingManagerCallback callback, Handler handler)
- throws MbmsException {
+ public static MbmsStreamingSession create(@NonNull Context context,
+ @NonNull MbmsStreamingSessionCallback callback, @NonNull Handler handler) {
return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), handler);
}
/**
- * Create a new MbmsStreamingManager using the system default data subscription ID and
- * default {@link Handler}.
- * See {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}.
- */
- public static MbmsStreamingManager create(Context context,
- MbmsStreamingManagerCallback callback)
- throws MbmsException {
- return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), null);
- }
-
- /**
- * Terminates this instance, ending calls to the registered listener. Also terminates
- * any streaming services spawned from this instance.
+ * Terminates this instance. Also terminates
+ * any streaming services spawned from this instance as if
+ * {@link StreamingService#stopStreaming()} had been called on them. After this method returns,
+ * no further callbacks originating from the middleware will be enqueued on the provided
+ * instance of {@link MbmsStreamingSessionCallback}, but callbacks that have already been
+ * enqueued will still be delivered.
+ *
+ * It is safe to call {@link #create(Context, MbmsStreamingSessionCallback, int, Handler)} to
+ * obtain another instance of {@link MbmsStreamingSession} immediately after this method
+ * returns.
*
* May throw an {@link IllegalStateException}
*/
- public void dispose() {
+ public void close() {
try {
IMbmsStreamingService streamingService = mService.get();
if (streamingService == null) {
@@ -164,47 +168,49 @@
return;
}
streamingService.dispose(mSubscriptionId);
+ for (StreamingService s : mKnownActiveStreamingServices) {
+ s.getCallback().stop();
+ }
+ mKnownActiveStreamingServices.clear();
} catch (RemoteException e) {
// Ignore for now
} finally {
mService.set(null);
sIsInitialized.set(false);
+ mInternalCallback.stop();
}
}
/**
* An inspection API to retrieve the list of streaming media currently be advertised.
- * The results are returned asynchronously through the previously registered callback.
- * serviceClasses lets the app filter on types of programming and is opaque data between
- * the app and the carrier.
+ * The results are returned asynchronously via
+ * {@link MbmsStreamingSessionCallback#onStreamingServicesUpdated(List)} on the callback
+ * provided upon creation.
*
- * Multiple calls replace the list of serviceClasses of interest.
+ * Multiple calls replace the list of service classes of interest.
*
- * This may throw an {@link MbmsException} containing any error in
- * {@link android.telephony.mbms.MbmsException.GeneralErrors},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or
- * {@link MbmsException#ERROR_MIDDLEWARE_LOST}.
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}.
*
- * May also throw an unchecked {@link IllegalArgumentException} or an
- * {@link IllegalStateException}
- *
- * @param classList A list of streaming service classes that the app would like updates on.
+ * @param serviceClassList A list of streaming service classes that the app would like updates
+ * on. The exact names of these classes should be negotiated with the
+ * wireless carrier separately.
*/
- public void getStreamingServices(List<String> classList) throws MbmsException {
+ public void requestUpdateStreamingServices(List<String> serviceClassList) {
IMbmsStreamingService streamingService = mService.get();
if (streamingService == null) {
- throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ throw new IllegalStateException("Middleware not yet bound");
}
try {
- int returnCode = streamingService.getStreamingServices(mSubscriptionId, classList);
+ int returnCode = streamingService.requestUpdateStreamingServices(
+ mSubscriptionId, serviceClassList);
if (returnCode != MbmsException.SUCCESS) {
- throw new MbmsException(returnCode);
+ sendErrorToApp(returnCode, null);
}
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
sIsInitialized.set(false);
- throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, null);
}
}
@@ -215,13 +221,7 @@
* reported via
* {@link android.telephony.mbms.StreamingServiceCallback#onStreamStateUpdated(int, int)}
*
- * May throw an
- * {@link MbmsException} containing any of the error codes in
- * {@link android.telephony.mbms.MbmsException.GeneralErrors},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or
- * {@link MbmsException#ERROR_MIDDLEWARE_LOST}.
- *
- * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
* Asynchronous errors through the callback include any of the errors in
* {@link android.telephony.mbms.MbmsException.GeneralErrors} or
@@ -229,42 +229,49 @@
*
* @param serviceInfo The information about the service to stream.
* @param callback A callback that'll be called when something about the stream changes.
- * @param handler A handler that calls to {@code callback} should be called on. If null,
- * defaults to the handler provided via
- * {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}.
+ * @param handler A handler that calls to {@code callback} should be called on.
* @return An instance of {@link StreamingService} through which the stream can be controlled.
+ * May be {@code null} if an error occurred.
*/
- public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
- StreamingServiceCallback callback, Handler handler) throws MbmsException {
+ public @Nullable StreamingService startStreaming(StreamingServiceInfo serviceInfo,
+ StreamingServiceCallback callback, @NonNull Handler handler) {
IMbmsStreamingService streamingService = mService.get();
if (streamingService == null) {
- throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ throw new IllegalStateException("Middleware not yet bound");
}
InternalStreamingServiceCallback serviceCallback = new InternalStreamingServiceCallback(
- callback, handler == null ? mInternalCallback.getHandler() : handler);
+ callback, handler);
StreamingService serviceForApp = new StreamingService(
- mSubscriptionId, streamingService, serviceInfo, serviceCallback);
+ mSubscriptionId, streamingService, this, serviceInfo, serviceCallback);
+ mKnownActiveStreamingServices.add(serviceForApp);
try {
int returnCode = streamingService.startStreaming(
mSubscriptionId, serviceInfo.getServiceId(), serviceCallback);
if (returnCode != MbmsException.SUCCESS) {
- throw new MbmsException(returnCode);
+ sendErrorToApp(returnCode, null);
+ return null;
}
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
sIsInitialized.set(false);
- throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, null);
+ return null;
}
return serviceForApp;
}
- private void bindAndInitialize() throws MbmsException {
- MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION,
+ /** @hide */
+ public void onStreamingServiceStopped(StreamingService service) {
+ mKnownActiveStreamingServices.remove(service);
+ }
+
+ private int bindAndInitialize() {
+ return MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION,
new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -315,7 +322,7 @@
private void sendErrorToApp(int errorCode, String message) {
try {
- mInternalCallback.error(errorCode, message);
+ mInternalCallback.onError(errorCode, message);
} catch (RemoteException e) {
// Ignore, should not happen locally.
}
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java
index 9300ef9..d8d7f48 100644
--- a/telephony/java/android/telephony/mbms/FileServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java
@@ -58,7 +58,7 @@
FileServiceInfo(Parcel in) {
super(in);
files = new ArrayList<FileInfo>();
- in.readList(files, null);
+ in.readList(files, FileInfo.class.getClassLoader());
}
@Override
diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl
similarity index 80%
rename from telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
rename to telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl
index 007aee7..0bf0ebc 100755
--- a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl
@@ -24,11 +24,11 @@
* The interface the clients top-level streaming listener will satisfy.
* @hide
*/
-oneway interface IMbmsStreamingManagerCallback
+oneway interface IMbmsStreamingSessionCallback
{
- void error(int errorCode, String message);
+ void onError(int errorCode, String message);
- void streamingServicesUpdated(in List<StreamingServiceInfo> services);
+ void onStreamingServicesUpdated(in List<StreamingServiceInfo> services);
- void middlewareReady();
+ void onMiddlewareReady();
}
diff --git a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
index 0952fbe..164cefb 100755
--- a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
@@ -20,9 +20,9 @@
* @hide
*/
oneway interface IStreamingServiceCallback {
- void error(int errorCode, String message);
- void streamStateUpdated(int state, int reason);
- void mediaDescriptionUpdated();
- void broadcastSignalStrengthUpdated(int signalStrength);
- void streamMethodUpdated(int methodType);
+ void onError(int errorCode, String message);
+ void onStreamStateUpdated(int state, int reason);
+ void onMediaDescriptionUpdated();
+ void onBroadcastSignalStrengthUpdated(int signalStrength);
+ void onStreamMethodUpdated(int methodType);
}
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
index bb337b2..28ee5f1 100644
--- a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
@@ -23,6 +23,7 @@
public class InternalStreamingServiceCallback extends IStreamingServiceCallback.Stub {
private final StreamingServiceCallback mAppCallback;
private final Handler mHandler;
+ private volatile boolean mIsStopped = false;
public InternalStreamingServiceCallback(StreamingServiceCallback appCallback, Handler handler) {
mAppCallback = appCallback;
@@ -30,7 +31,11 @@
}
@Override
- public void error(int errorCode, String message) throws RemoteException {
+ public void onError(int errorCode, String message) throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -40,7 +45,11 @@
}
@Override
- public void streamStateUpdated(int state, int reason) throws RemoteException {
+ public void onStreamStateUpdated(int state, int reason) throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -50,7 +59,11 @@
}
@Override
- public void mediaDescriptionUpdated() throws RemoteException {
+ public void onMediaDescriptionUpdated() throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -60,7 +73,11 @@
}
@Override
- public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException {
+ public void onBroadcastSignalStrengthUpdated(int signalStrength) throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -70,7 +87,11 @@
}
@Override
- public void streamMethodUpdated(int methodType) throws RemoteException {
+ public void onStreamMethodUpdated(int methodType) throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -78,4 +99,8 @@
}
});
}
+
+ public void stop() {
+ mIsStopped = true;
+ }
}
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
similarity index 69%
rename from telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java
rename to telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
index b52df8c..0d890b8 100644
--- a/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
@@ -18,25 +18,27 @@
import android.os.Handler;
import android.os.RemoteException;
-import android.telephony.mbms.IMbmsStreamingManagerCallback;
-import android.telephony.mbms.MbmsStreamingManagerCallback;
-import android.telephony.mbms.StreamingServiceInfo;
import java.util.List;
/** @hide */
-public class InternalStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub {
+public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallback.Stub {
private final Handler mHandler;
- private final MbmsStreamingManagerCallback mAppCallback;
+ private final MbmsStreamingSessionCallback mAppCallback;
+ private volatile boolean mIsStopped = false;
- public InternalStreamingManagerCallback(MbmsStreamingManagerCallback appCallback,
+ public InternalStreamingSessionCallback(MbmsStreamingSessionCallback appCallback,
Handler handler) {
mAppCallback = appCallback;
mHandler = handler;
}
@Override
- public void error(int errorCode, String message) throws RemoteException {
+ public void onError(int errorCode, String message) throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -46,8 +48,12 @@
}
@Override
- public void streamingServicesUpdated(List<StreamingServiceInfo> services)
+ public void onStreamingServicesUpdated(List<StreamingServiceInfo> services)
throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -57,7 +63,11 @@
}
@Override
- public void middlewareReady() throws RemoteException {
+ public void onMiddlewareReady() throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -69,4 +79,8 @@
public Handler getHandler() {
return mHandler;
}
+
+ public void stop() {
+ mIsStopped = true;
+ }
}
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index 56cd8de..5b069cb 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -16,6 +16,8 @@
package android.telephony.mbms;
+import android.telephony.MbmsStreamingSession;
+
public class MbmsException extends Exception {
/** Indicates that the operation was successful. */
public static final int SUCCESS = 0;
@@ -31,7 +33,7 @@
/**
* Indicates that the app attempted to perform an operation on an instance of
* TODO link android.telephony.MbmsDownloadManager or
- * {@link android.telephony.MbmsStreamingManager} without being bound to the middleware.
+ * {@link MbmsStreamingSession} without being bound to the middleware.
*/
public static final int ERROR_MIDDLEWARE_NOT_BOUND = 2;
@@ -46,7 +48,7 @@
private InitializationErrors() {}
/**
* Indicates that the app tried to create more than one instance each of
- * {@link android.telephony.MbmsStreamingManager} or
+ * {@link MbmsStreamingSession} or
* TODO link android.telephony.MbmsDownloadManager
*/
public static final int ERROR_DUPLICATE_INITIALIZE = 101;
@@ -64,7 +66,7 @@
private GeneralErrors() {}
/**
* Indicates that the app attempted to perform an operation before receiving notification
- * that the middleware is ready via {@link MbmsStreamingManagerCallback#onMiddlewareReady()}
+ * that the middleware is ready via {@link MbmsStreamingSessionCallback#onMiddlewareReady()}
* or TODO: link MbmsDownloadManagerCallback#middlewareReady
*/
public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201;
@@ -107,7 +109,7 @@
/**
* Indicates that the app called
- * {@link android.telephony.MbmsStreamingManager#startStreaming(
+ * {@link MbmsStreamingSession#startStreaming(
* StreamingServiceInfo, StreamingServiceCallback, android.os.Handler)}
* more than once for the same {@link StreamingServiceInfo}.
*/
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
similarity index 76%
rename from telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
rename to telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
index b31ffa7..4a70c00 100644
--- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
@@ -16,25 +16,26 @@
package android.telephony.mbms;
+import android.annotation.Nullable;
import android.content.Context;
-import android.os.RemoteException;
-import android.telephony.MbmsStreamingManager;
+import android.os.Handler;
+import android.telephony.MbmsStreamingSession;
import java.util.List;
/**
* A callback class that is used to receive information from the middleware on MBMS streaming
* services. An instance of this object should be passed into
- * {@link android.telephony.MbmsStreamingManager#create(Context, MbmsStreamingManagerCallback)}.
+ * {@link MbmsStreamingSession#create(Context, MbmsStreamingSessionCallback, int, Handler)}.
*/
-public class MbmsStreamingManagerCallback {
+public class MbmsStreamingSessionCallback {
/**
* Called by the middleware when it has detected an error condition. The possible error codes
* are listed in {@link MbmsException}.
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- public void onError(int errorCode, String message) {
+ public void onError(int errorCode, @Nullable String message) {
// default implementation empty
}
@@ -47,8 +48,7 @@
* call with the same service class list would return different
* results.
*
- * @param services a List of StreamingServiceInfos
- *
+ * @param services The list of available services.
*/
public void onStreamingServicesUpdated(List<StreamingServiceInfo> services) {
// default implementation empty
@@ -58,9 +58,9 @@
* Called to indicate that the middleware has been initialized and is ready.
*
* Before this method is called, calling any method on an instance of
- * {@link android.telephony.MbmsStreamingManager} will result in an {@link MbmsException}
- * being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
+ * {@link MbmsStreamingSession} will result in an {@link IllegalStateException} or an error
+ * delivered via {@link #onError(int, String)} with error code
+ * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
*/
public void onMiddlewareReady() {
// default implementation empty
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index 4b913f8..8652b3e 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -68,19 +68,20 @@
return downloadServices.get(0).serviceInfo;
}
- public static void startBinding(Context context, String serviceAction,
- ServiceConnection serviceConnection) throws MbmsException {
+ public static int startBinding(Context context, String serviceAction,
+ ServiceConnection serviceConnection) {
Intent bindIntent = new Intent();
ServiceInfo mbmsServiceInfo =
MbmsUtils.getMiddlewareServiceInfo(context, serviceAction);
if (mbmsServiceInfo == null) {
- throw new MbmsException(MbmsException.ERROR_NO_UNIQUE_MIDDLEWARE);
+ return MbmsException.ERROR_NO_UNIQUE_MIDDLEWARE;
}
bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo));
context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
+ return MbmsException.SUCCESS;
}
/**
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index 5764cfb..e5d1d3b 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -123,7 +123,7 @@
/**
* The class name for this service - used to categorize and filter
*/
- public String getClassName() {
+ public String getServiceClassName() {
return className;
}
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 1d66bac..1a36fc1 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -17,8 +17,10 @@
package android.telephony.mbms;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.net.Uri;
import android.os.RemoteException;
+import android.telephony.MbmsStreamingSession;
import android.telephony.mbms.vendor.IMbmsStreamingService;
import android.util.Log;
@@ -27,7 +29,7 @@
/**
* Class used to represent a single MBMS stream. After a stream has been started with
- * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo,
+ * {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo,
* StreamingServiceCallback, android.os.Handler)},
* this class is used to hold information about the stream and control it.
*/
@@ -63,7 +65,7 @@
/**
* State changed due to a call to {@link #stopStreaming()} or
- * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo,
+ * {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo,
* StreamingServiceCallback, android.os.Handler)}
*/
public static final int REASON_BY_USER_REQUEST = 1;
@@ -101,6 +103,7 @@
public final static int UNICAST_METHOD = 2;
private final int mSubscriptionId;
+ private final MbmsStreamingSession mParentSession;
private final StreamingServiceInfo mServiceInfo;
private final InternalStreamingServiceCallback mCallback;
@@ -111,25 +114,25 @@
*/
public StreamingService(int subscriptionId,
IMbmsStreamingService service,
+ MbmsStreamingSession session,
StreamingServiceInfo streamingServiceInfo,
InternalStreamingServiceCallback callback) {
mSubscriptionId = subscriptionId;
+ mParentSession = session;
mService = service;
mServiceInfo = streamingServiceInfo;
mCallback = callback;
}
/**
- * Retreive the Uri used to play this stream.
+ * Retrieve the Uri used to play this stream.
*
- * This may throw a {@link MbmsException} with the error code
- * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}.
*
- * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
- *
- * @return The {@link Uri} to pass to the streaming client.
+ * @return The {@link Uri} to pass to the streaming client, or {@code null} if an error
+ * occurred.
*/
- public Uri getPlaybackUri() throws MbmsException {
+ public @Nullable Uri getPlaybackUri() {
if (mService == null) {
throw new IllegalStateException("No streaming service attached");
}
@@ -139,25 +142,26 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
- throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ mParentSession.onStreamingServiceStopped(this);
+ sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, null);
+ return null;
}
}
/**
- * Retreive the info for this StreamingService.
+ * Retrieve the {@link StreamingServiceInfo} corresponding to this stream.
*/
public StreamingServiceInfo getInfo() {
return mServiceInfo;
}
/**
- * Stop streaming this service.
- * This may throw a {@link MbmsException} with the error code
- * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ * Stop streaming this service. Further operations on this object will fail with an
+ * {@link IllegalStateException}.
*
- * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*/
- public void stopStreaming() throws MbmsException {
+ public void stopStreaming() {
if (mService == null) {
throw new IllegalStateException("No streaming service attached");
}
@@ -167,32 +171,22 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
- throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, null);
+ } finally {
+ mParentSession.onStreamingServiceStopped(this);
}
}
- /**
- * Disposes of this stream. Further operations on this object will fail with an
- * {@link IllegalStateException}.
- *
- * This may throw a {@link MbmsException} with the error code
- * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
- * May also throw an {@link IllegalStateException}
- */
- public void dispose() throws MbmsException {
- if (mService == null) {
- throw new IllegalStateException("No streaming service attached");
- }
+ /** @hide */
+ public InternalStreamingServiceCallback getCallback() {
+ return mCallback;
+ }
+ private void sendErrorToApp(int errorCode, String message) {
try {
- mService.disposeStream(mSubscriptionId, mServiceInfo.getServiceId());
+ mCallback.onError(errorCode, message);
} catch (RemoteException e) {
- Log.w(LOG_TAG, "Remote process died");
- throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
- } catch (IllegalArgumentException e) {
- throw new IllegalStateException("StreamingService state inconsistent with middleware");
- } finally {
- mService = null;
+ // Ignore, should not happen locally.
}
}
}
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
index b72c715..a50a469 100644
--- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
@@ -16,6 +16,8 @@
package android.telephony.mbms;
+import android.annotation.Nullable;
+
/**
* A callback class for use when the application is actively streaming content. The middleware
* will provide updates on the status of the stream via this callback.
@@ -37,7 +39,7 @@
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- public void onError(int errorCode, String message) {
+ public void onError(int errorCode, @Nullable String message) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index 4dd4292..c90ffc7 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -17,7 +17,7 @@
package android.telephony.mbms.vendor;
import android.net.Uri;
-import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IMbmsStreamingSessionCallback;
import android.telephony.mbms.IStreamingServiceCallback;
import android.telephony.mbms.StreamingServiceInfo;
@@ -26,18 +26,16 @@
*/
interface IMbmsStreamingService
{
- int initialize(IMbmsStreamingManagerCallback listener, int subId);
+ int initialize(IMbmsStreamingSessionCallback callback, int subId);
- int getStreamingServices(int subId, in List<String> serviceClasses);
+ int requestUpdateStreamingServices(int subId, in List<String> serviceClasses);
int startStreaming(int subId, String serviceId,
- IStreamingServiceCallback listener);
+ IStreamingServiceCallback callback);
Uri getPlaybackUri(int subId, String serviceId);
void stopStreaming(int subId, String serviceId);
- void disposeStream(int subId, String serviceId);
-
void dispose(int subId);
}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index 626a681..1a4d0d8 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -22,10 +22,10 @@
import android.net.Uri;
import android.os.Binder;
import android.os.RemoteException;
-import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IMbmsStreamingSessionCallback;
import android.telephony.mbms.IStreamingServiceCallback;
import android.telephony.mbms.MbmsException;
-import android.telephony.mbms.MbmsStreamingManagerCallback;
+import android.telephony.mbms.MbmsStreamingSessionCallback;
import android.telephony.mbms.StreamingService;
import android.telephony.mbms.StreamingServiceCallback;
import android.telephony.mbms.StreamingServiceInfo;
@@ -48,12 +48,12 @@
*
* May return any value from {@link android.telephony.mbms.MbmsException.InitializationErrors}
* or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via
- * {@link IMbmsStreamingManagerCallback#error(int, String)}.
+ * {@link IMbmsStreamingSessionCallback#onError(int, String)}.
*
* @param callback The callback to use to communicate with the app.
* @param subscriptionId The subscription ID to use.
*/
- public int initialize(MbmsStreamingManagerCallback callback, int subscriptionId)
+ public int initialize(MbmsStreamingSessionCallback callback, int subscriptionId)
throws RemoteException {
return 0;
}
@@ -63,7 +63,7 @@
* @hide
*/
@Override
- public final int initialize(final IMbmsStreamingManagerCallback callback,
+ public final int initialize(final IMbmsStreamingSessionCallback callback,
final int subscriptionId) throws RemoteException {
final int uid = Binder.getCallingUid();
callback.asBinder().linkToDeath(new DeathRecipient() {
@@ -73,11 +73,11 @@
}
}, 0);
- return initialize(new MbmsStreamingManagerCallback() {
+ return initialize(new MbmsStreamingSessionCallback() {
@Override
public void onError(int errorCode, String message) {
try {
- callback.error(errorCode, message);
+ callback.onError(errorCode, message);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -86,7 +86,7 @@
@Override
public void onStreamingServicesUpdated(List<StreamingServiceInfo> services) {
try {
- callback.streamingServicesUpdated(services);
+ callback.onStreamingServicesUpdated(services);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -95,7 +95,7 @@
@Override
public void onMiddlewareReady() {
try {
- callback.middlewareReady();
+ callback.onMiddlewareReady();
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -107,7 +107,7 @@
/**
* Registers serviceClasses of interest with the appName/subId key.
* Starts async fetching data on streaming services of matching classes to be reported
- * later via {@link IMbmsStreamingManagerCallback#streamingServicesUpdated(List)}
+ * later via {@link IMbmsStreamingSessionCallback#onStreamingServicesUpdated(List)}
*
* Note that subsequent calls with the same uid and subId will replace
* the service class list.
@@ -122,7 +122,7 @@
* {@link android.telephony.mbms.MbmsException.GeneralErrors}
*/
@Override
- public int getStreamingServices(int subscriptionId,
+ public int requestUpdateStreamingServices(int subscriptionId,
List<String> serviceClasses) throws RemoteException {
return 0;
}
@@ -130,7 +130,7 @@
/**
* Starts streaming on a particular service. This method may perform asynchronous work. When
* the middleware is ready to send bits to the frontend, it should inform the app via
- * {@link IStreamingServiceCallback#streamStateUpdated(int, int)}.
+ * {@link IStreamingServiceCallback#onStreamStateUpdated(int, int)}.
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
@@ -164,7 +164,7 @@
@Override
public void onError(int errorCode, String message) {
try {
- callback.error(errorCode, message);
+ callback.onError(errorCode, message);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -174,7 +174,7 @@
public void onStreamStateUpdated(@StreamingService.StreamingState int state,
@StreamingService.StreamingStateChangeReason int reason) {
try {
- callback.streamStateUpdated(state, reason);
+ callback.onStreamStateUpdated(state, reason);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -183,7 +183,7 @@
@Override
public void onMediaDescriptionUpdated() {
try {
- callback.mediaDescriptionUpdated();
+ callback.onMediaDescriptionUpdated();
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -192,7 +192,7 @@
@Override
public void onBroadcastSignalStrengthUpdated(int signalStrength) {
try {
- callback.broadcastSignalStrengthUpdated(signalStrength);
+ callback.onBroadcastSignalStrengthUpdated(signalStrength);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -201,7 +201,7 @@
@Override
public void onStreamMethodUpdated(int methodType) {
try {
- callback.streamMethodUpdated(methodType);
+ callback.onStreamMethodUpdated(methodType);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
}
@@ -228,7 +228,11 @@
/**
* Stop streaming the stream identified by {@code serviceId}. Notification of the resulting
* stream state change should be reported to the app via
- * {@link IStreamingServiceCallback#streamStateUpdated(int, int)}.
+ * {@link IStreamingServiceCallback#onStreamStateUpdated(int, int)}.
+ *
+ * In addition, the callback provided via
+ * {@link #startStreaming(int, String, IStreamingServiceCallback)} should no longer be
+ * used after this method has called by the app.
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
@@ -241,27 +245,10 @@
}
/**
- * Dispose of the stream identified by {@code serviceId} for the app identified by the
- * {@code appName} and {@code subscriptionId} arguments along with the caller's uid.
- * No notification back to the app is required for this operation, and the callback provided via
- * {@link #startStreaming(int, String, IStreamingServiceCallback)} should no longer be
- * used after this method has called by the app.
- *
- * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
- *
- * @param subscriptionId The subscription id to use.
- * @param serviceId The ID of the streaming service that the app wishes to dispose of.
- */
- @Override
- public void disposeStream(int subscriptionId, String serviceId)
- throws RemoteException {
- }
-
- /**
* Signals that the app wishes to dispose of the session identified by the
* {@code subscriptionId} argument and the caller's uid. No notification back to the
* app is required for this operation, and the corresponding callback provided via
- * {@link #initialize(IMbmsStreamingManagerCallback, int)} should no longer be used
+ * {@link #initialize(IMbmsStreamingSessionCallback, int)} should no longer be used
* after this method has been called by the app.
*
* May throw an {@link IllegalStateException}
diff --git a/tests/net/java/android/net/ip/IpManagerTest.java b/tests/net/java/android/net/ip/IpManagerTest.java
index 541f91ad..22d88fb 100644
--- a/tests/net/java/android/net/ip/IpManagerTest.java
+++ b/tests/net/java/android/net/ip/IpManagerTest.java
@@ -180,7 +180,8 @@
// Add N - 1 addresses
for (int i = 0; i < lastAddr; i++) {
mObserver.addressUpdated(iface, new LinkAddress(addresses[i]));
- verify(mCb, timeout(100).times(1)).onLinkPropertiesChange(any());
+ verify(mCb, timeout(100)).onLinkPropertiesChange(any());
+ reset(mCb);
}
// Add Nth address
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
index 9115378..0a5a6aa 100644
--- a/tests/net/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/net/java/android/net/nsd/NsdManagerTest.java
@@ -60,7 +60,7 @@
NsdManager mManager;
- long mTimeoutMs = 100; // non-final so that tests can adjust the value.
+ long mTimeoutMs = 200; // non-final so that tests can adjust the value.
@Before
public void setUp() throws Exception {
@@ -74,7 +74,7 @@
@After
public void tearDown() throws Exception {
- waitForIdleHandler(mServiceHandler, mTimeoutMs);
+ mServiceHandler.waitForIdle(mTimeoutMs);
mServiceHandler.chan.disconnect();
mServiceHandler.stop();
if (mManager != null) {
@@ -334,9 +334,10 @@
}
int verifyRequest(int expectedMessageType) {
+ mServiceHandler.waitForIdle(mTimeoutMs);
verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
reset(mServiceHandler);
- Message received = mServiceHandler.lastMessage;
+ Message received = mServiceHandler.getLastMessage();
assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
return received.arg2;
}
@@ -347,31 +348,43 @@
// Implements the server side of AsyncChannel connection protocol
public static class MockServiceHandler extends Handler {
- public Context mContext;
+ public final Context context;
public AsyncChannel chan;
- public volatile Message lastMessage;
+ public Message lastMessage;
- MockServiceHandler(Looper looper, Context context) {
- super(looper);
- mContext = context;
+ MockServiceHandler(Looper l, Context c) {
+ super(l);
+ context = c;
+ }
+
+ synchronized Message getLastMessage() {
+ return lastMessage;
+ }
+
+ synchronized void setLastMessage(Message msg) {
+ lastMessage = obtainMessage();
+ lastMessage.copyFrom(msg);
+ }
+
+ void waitForIdle(long timeoutMs) {
+ waitForIdleHandler(this, timeoutMs);
}
@Override
public void handleMessage(Message msg) {
- lastMessage = obtainMessage();
- lastMessage.copyFrom(msg);
+ setLastMessage(msg);
if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
chan = new AsyncChannel();
- chan.connect(mContext, this, msg.replyTo);
+ chan.connect(context, this, msg.replyTo);
chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
}
}
- public void stop() {
+ void stop() {
getLooper().quitSafely();
}
- public static MockServiceHandler create(Context context) {
+ static MockServiceHandler create(Context context) {
HandlerThread t = new HandlerThread("mock-service-handler");
t.start();
return new MockServiceHandler(t.getLooper(), context);
diff --git a/tests/net/java/com/android/internal/util/TestUtils.java b/tests/net/java/com/android/internal/util/TestUtils.java
index c9fa340..6db01d3 100644
--- a/tests/net/java/com/android/internal/util/TestUtils.java
+++ b/tests/net/java/com/android/internal/util/TestUtils.java
@@ -30,8 +30,7 @@
* Block until the given Handler thread becomes idle, or until timeoutMs has passed.
*/
public static void waitForIdleHandler(HandlerThread handlerThread, long timeoutMs) {
- // TODO: convert to getThreadHandler once it is available on aosp
- waitForIdleLooper(handlerThread.getLooper(), timeoutMs);
+ waitForIdleHandler(handlerThread.getThreadHandler(), timeoutMs);
}
/**
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8816d43..a814738 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -683,7 +683,8 @@
public WrappedNetworkMonitor(Context context, Handler handler,
NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
IpConnectivityLog log) {
- super(context, handler, networkAgentInfo, defaultRequest, log);
+ super(context, handler, networkAgentInfo, defaultRequest, log,
+ NetworkMonitor.NetworkMonitorSettings.DEFAULT);
}
@Override
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index eff04ab..f72a1c6 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity;
+import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
+import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
import static com.android.server.connectivity.MetricsTestUtil.aBool;
import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
import static com.android.server.connectivity.MetricsTestUtil.aLong;
@@ -31,29 +33,41 @@
import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.ETHERNET;
import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE;
import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.WIFI;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import android.net.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
+import android.net.metrics.ConnectStats;
import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent;
import android.net.metrics.DnsEvent;
+import android.net.metrics.DnsEvent;
import android.net.metrics.IpManagerEvent;
import android.net.metrics.IpReachabilityEvent;
import android.net.metrics.NetworkEvent;
import android.net.metrics.RaEvent;
import android.net.metrics.ValidationProbeEvent;
+import android.net.metrics.WakeupStats;
+import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
+
import java.util.Arrays;
import java.util.List;
-import junit.framework.TestCase;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
// TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
-public class IpConnectivityEventBuilderTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpConnectivityEventBuilderTest {
- @SmallTest
+ @Test
public void testLinkLayerInferrence() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpReachabilityEvent.class),
@@ -182,7 +196,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testDefaultNetworkEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(DefaultNetworkEvent.class),
@@ -223,7 +237,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testDhcpClientEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(DhcpClientEvent.class),
@@ -249,7 +263,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testDhcpErrorEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(DhcpErrorEvent.class),
@@ -274,7 +288,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testIpManagerEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpManagerEvent.class),
@@ -300,7 +314,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testIpReachabilityEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpReachabilityEvent.class),
@@ -324,7 +338,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testNetworkEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(NetworkEvent.class),
@@ -353,7 +367,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testValidationProbeEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(ValidationProbeEvent.class),
@@ -380,7 +394,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testApfProgramEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(ApfProgramEvent.class),
@@ -414,7 +428,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testApfStatsSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(ApfStats.class),
@@ -457,7 +471,7 @@
verifySerialization(want, ev);
}
- @SmallTest
+ @Test
public void testRaEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(RaEvent.class),
@@ -490,11 +504,49 @@
verifySerialization(want, ev);
}
+ @Test
+ public void testWakeupStatsSerialization() {
+ WakeupStats stats = new WakeupStats("wlan0");
+ stats.totalWakeups = 14;
+ stats.applicationWakeups = 5;
+ stats.nonApplicationWakeups = 1;
+ stats.rootWakeups = 2;
+ stats.systemWakeups = 3;
+ stats.unroutedWakeups = 3;
+
+ IpConnectivityEvent got = IpConnectivityEventBuilder.toProto(stats);
+ String want = String.join("\n",
+ "dropped_events: 0",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " wakeup_stats <",
+ " application_wakeups: 5",
+ " duration_sec: 0",
+ " non_application_wakeups: 1",
+ " root_wakeups: 2",
+ " system_wakeups: 3",
+ " total_wakeups: 14",
+ " unrouted_wakeups: 3",
+ " >",
+ ">",
+ "version: 2\n");
+
+ verifySerialization(want, got);
+ }
+
static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
+ List<IpConnectivityEvent> protoInput =
+ IpConnectivityEventBuilder.toProto(Arrays.asList(input));
+ verifySerialization(want, protoInput.toArray(new IpConnectivityEvent[0]));
+ }
+
+ static void verifySerialization(String want, IpConnectivityEvent... input) {
try {
- List<IpConnectivityEvent> proto =
- IpConnectivityEventBuilder.toProto(Arrays.asList(input));
- byte[] got = IpConnectivityEventBuilder.serialize(0, proto);
+ byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
assertEquals(want, log.toString());
} catch (Exception e) {
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index cc18b7f..ede5988 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -224,6 +224,15 @@
dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34);
+ // iface, uid
+ wakeupEvent("wlan0", 1000);
+ wakeupEvent("rmnet0", 10123);
+ wakeupEvent("wlan0", 1000);
+ wakeupEvent("rmnet0", 10008);
+ wakeupEvent("wlan0", -1);
+ wakeupEvent("wlan0", 10008);
+ wakeupEvent("rmnet0", 1000);
+
String want = String.join("\n",
"dropped_events: 0",
"events <",
@@ -405,6 +414,38 @@
" return_codes: 0",
" >",
">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 2",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " wakeup_stats <",
+ " application_wakeups: 2",
+ " duration_sec: 0",
+ " non_application_wakeups: 0",
+ " root_wakeups: 0",
+ " system_wakeups: 1",
+ " total_wakeups: 3",
+ " unrouted_wakeups: 0",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " wakeup_stats <",
+ " application_wakeups: 1",
+ " duration_sec: 0",
+ " non_application_wakeups: 0",
+ " root_wakeups: 0",
+ " system_wakeups: 2",
+ " total_wakeups: 4",
+ " unrouted_wakeups: 1",
+ " >",
+ ">",
"version: 2\n");
verifySerialization(want, getdump("flush"));
@@ -425,6 +466,11 @@
mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}
+ void wakeupEvent(String iface, int uid) throws Exception {
+ String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
+ mNetdListener.onWakeupEvent(prefix, uid, uid, 0);
+ }
+
List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
ArgumentCaptor<ConnectivityMetricsEvent> captor =
ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 46f395e..2b105e5 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -19,6 +19,7 @@
import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
@@ -37,9 +38,11 @@
import android.system.OsConstants;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Base64;
+
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.DNSLookupBatch;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
+
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -47,6 +50,7 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -75,6 +79,118 @@
}
@Test
+ public void testWakeupEventLogging() throws Exception {
+ final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
+
+ // Assert no events
+ String[] events1 = listNetdEvent();
+ assertEquals(new String[]{""}, events1);
+
+ long now = System.currentTimeMillis();
+ String prefix = "iface:wlan0";
+ int[] uids = { 10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004 };
+ for (int uid : uids) {
+ mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
+ }
+
+ String[] events2 = listNetdEvent();
+ int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
+ assertEquals(expectedLength2, events2.length);
+ assertContains(events2[0], "WakeupStats");
+ assertContains(events2[0], "wlan0");
+ for (int i = 0; i < uids.length; i++) {
+ String got = events2[i+1];
+ assertContains(got, "WakeupEvent");
+ assertContains(got, "wlan0");
+ assertContains(got, "uid: " + uids[i]);
+ }
+
+ int uid = 20000;
+ for (int i = 0; i < BUFFER_LENGTH * 2; i++) {
+ long ts = now + 10;
+ mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts);
+ }
+
+ String[] events3 = listNetdEvent();
+ int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
+ assertEquals(expectedLength3, events3.length);
+ assertContains(events2[0], "WakeupStats");
+ assertContains(events2[0], "wlan0");
+ for (int i = 1; i < expectedLength3; i++) {
+ String got = events3[i];
+ assertContains(got, "WakeupEvent");
+ assertContains(got, "wlan0");
+ assertContains(got, "uid: " + uid);
+ }
+
+ uid = 45678;
+ mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
+
+ String[] events4 = listNetdEvent();
+ String lastEvent = events4[events4.length - 1];
+ assertContains(lastEvent, "WakeupEvent");
+ assertContains(lastEvent, "wlan0");
+ assertContains(lastEvent, "uid: " + uid);
+ }
+
+ @Test
+ public void testWakeupStatsLogging() throws Exception {
+ wakeupEvent("wlan0", 1000);
+ wakeupEvent("rmnet0", 10123);
+ wakeupEvent("wlan0", 1000);
+ wakeupEvent("rmnet0", 10008);
+ wakeupEvent("wlan0", -1);
+ wakeupEvent("wlan0", 10008);
+ wakeupEvent("rmnet0", 1000);
+ wakeupEvent("wlan0", 10004);
+ wakeupEvent("wlan0", 1000);
+ wakeupEvent("wlan0", 0);
+ wakeupEvent("wlan0", -1);
+ wakeupEvent("rmnet0", 10052);
+ wakeupEvent("wlan0", 0);
+ wakeupEvent("rmnet0", 1000);
+ wakeupEvent("wlan0", 1010);
+
+ String got = flushStatistics();
+ String want = String.join("\n",
+ "dropped_events: 0",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 2",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " wakeup_stats <",
+ " application_wakeups: 3",
+ " duration_sec: 0",
+ " non_application_wakeups: 0",
+ " root_wakeups: 0",
+ " system_wakeups: 2",
+ " total_wakeups: 5",
+ " unrouted_wakeups: 0",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " wakeup_stats <",
+ " application_wakeups: 2",
+ " duration_sec: 0",
+ " non_application_wakeups: 1",
+ " root_wakeups: 2",
+ " system_wakeups: 3",
+ " total_wakeups: 10",
+ " unrouted_wakeups: 2",
+ " >",
+ ">",
+ "version: 2\n");
+ assertEquals(want, got);
+ }
+
+ @Test
public void testDnsLogging() throws Exception {
asyncDump(100);
@@ -297,6 +413,11 @@
mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}
+ void wakeupEvent(String iface, int uid) throws Exception {
+ String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
+ mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, 0);
+ }
+
void asyncDump(long durationMs) throws Exception {
final long stop = System.currentTimeMillis() + durationMs;
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
@@ -329,4 +450,15 @@
}
return log.toString();
}
+
+ String[] listNetdEvent() throws Exception {
+ StringWriter buffer = new StringWriter();
+ PrintWriter writer = new PrintWriter(buffer);
+ mNetdEventListenerService.list(writer);
+ return buffer.toString().split("\\n");
+ }
+
+ static void assertContains(String got, String want) {
+ assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java
new file mode 100644
index 0000000..27a897d
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.metrics.IpConnectivityLog;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.TelephonyManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkMonitorTest {
+
+ static final int TEST_ID = 60; // should be less than min netid 100
+
+ @Mock Context mContext;
+ @Mock Handler mHandler;
+ @Mock IpConnectivityLog mLogger;
+ @Mock NetworkAgentInfo mAgent;
+ @Mock NetworkMonitor.NetworkMonitorSettings mSettings;
+ @Mock NetworkRequest mRequest;
+ @Mock TelephonyManager mTelephony;
+ @Mock WifiManager mWifi;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mAgent.network()).thenReturn(new Network(TEST_ID));
+ when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
+ when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
+ }
+
+ NetworkMonitor makeMonitor() {
+ return new NetworkMonitor(mContext, mHandler, mAgent, mRequest, mLogger, mSettings);
+ }
+
+ @Test
+ public void testCreatingNetworkMonitor() {
+ NetworkMonitor monitor = makeMonitor();
+ }
+}
+