[DPM] DO can start network logging and listen for events
This CL adds:
1) Setter and getter in DPM to manipulate logging switch (retrieval
method to come in a subsequent CL(s)).
2) A way for DPM to register to listen for events.
3) Skeleton of NetworkLogger class (more to come in subsequent CL(s)).
Bug: 29748723
Change-Id: I5c04662ccc6febd2ba294b0eaca1ed1da9c16e47
diff --git a/Android.mk b/Android.mk
index db63739..09bdea2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -205,6 +205,7 @@
core/java/android/net/IIpConnectivityMetrics.aidl \
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
+ core/java/android/net/INetdEventCallback.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 118e1f3..138ec02 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6635,4 +6635,46 @@
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Called by a device owner to control the network logging feature. Logging can only be
+ * enabled on single user devices where the sole user is managed by the device owner. If a new
+ * user is added on the device, logging is disabled.
+ *
+ * <p> Network logs contain DNS lookup and connect() library call events.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param enabled whether network logging should be enabled or not.
+ * @throws {@link SecurityException} if {@code admin} is not a device owner.
+ * @throws {@link RemoteException} if network logging could not be enabled or disabled due to
+ * the logging service not being available
+ *
+ * @hide
+ */
+ public void setNetworkLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
+ throwIfParentInstance("setNetworkLoggingEnabled");
+ try {
+ mService.setNetworkLoggingEnabled(admin, enabled);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return whether network logging is enabled by a device owner.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return {@code true} if network logging is enabled by device owner, {@code false} otherwise.
+ * @throws {@link SecurityException} if {@code admin} is not a device owner.
+ *
+ * @hide
+ */
+ public boolean isNetworkLoggingEnabled(@NonNull ComponentName admin) {
+ throwIfParentInstance("isNetworkLoggingEnabled");
+ try {
+ return mService.isNetworkLoggingEnabled(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 22219d7..3cfa1e8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -314,4 +314,7 @@
void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
boolean isBackupServiceEnabled(in ComponentName admin);
+
+ void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled);
+ boolean isNetworkLoggingEnabled(in ComponentName admin);
}
diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
index d36b766..6f07b31 100644
--- a/core/java/android/net/IIpConnectivityMetrics.aidl
+++ b/core/java/android/net/IIpConnectivityMetrics.aidl
@@ -18,6 +18,7 @@
import android.os.Parcelable;
import android.net.ConnectivityMetricsEvent;
+import android.net.INetdEventCallback;
/** {@hide} */
interface IIpConnectivityMetrics {
@@ -27,4 +28,13 @@
* or -1 if the event was dropped due to rate limiting.
*/
int logEvent(in ConnectivityMetricsEvent event);
+
+ /**
+ * At most one callback can be registered (by DevicePolicyManager).
+ * @return status {@code true} if registering/unregistering of the callback was successful,
+ * {@code false} otherwise (might happen if IIpConnectivityMetrics is not available,
+ * if it happens make sure you call it when the service is up in the caller)
+ */
+ boolean registerNetdEventCallback(in INetdEventCallback callback);
+ boolean unregisterNetdEventCallback();
}
diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl
new file mode 100644
index 0000000..49436be
--- /dev/null
+++ b/core/java/android/net/INetdEventCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/** {@hide} */
+oneway interface INetdEventCallback {
+
+ /**
+ * Reports a single DNS lookup function call.
+ * This method must not block or perform long-running operations.
+ *
+ * @param hostname the name that was looked up.
+ * @param ipAddresses (possibly a subset of) the IP addresses returned.
+ * At most {@link #DNS_REPORTED_IP_ADDRESSES_LIMIT} addresses are logged.
+ * @param ipAddressesCount the number of IP addresses returned. May be different from the length
+ * of ipAddresses if there were too many addresses to log.
+ * @param timestamp the timestamp at which the query was reported by netd.
+ * @param uid the UID of the application that performed the query.
+ */
+ void onDnsEvent(String hostname, in String[] ipAddresses, int ipAddressesCount, long timestamp,
+ int uid);
+
+ /**
+ * Reports a single connect library call.
+ * This method must not block or perform long-running operations.
+ *
+ * @param ipAddr destination IP address.
+ * @param port destination port number.
+ * @param timestamp the timestamp at which the call was reported by netd.
+ * @param uid the UID of the application that performed the connection.
+ */
+ void onConnectEvent(String ipAddr, int port, long timestamp, int uid);
+}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index be68173..641c62f 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -19,10 +19,13 @@
import android.content.Context;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
+import android.net.INetdEventCallback;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
+import android.os.Binder;
import android.os.IBinder;
import android.os.Parcelable;
+import android.os.Process;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -263,6 +266,33 @@
private void enforcePermission(String what) {
getContext().enforceCallingOrSelfPermission(what, "IpConnectivityMetrics");
}
+
+ private void enforceNetdEventListeningPermission() {
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID) {
+ throw new SecurityException(String.format("Uid %d has no permission to listen for"
+ + " netd events.", uid));
+ }
+ }
+
+ @Override
+ public boolean registerNetdEventCallback(INetdEventCallback callback) {
+ enforceNetdEventListeningPermission();
+ if (mNetdListener == null) {
+ return false;
+ }
+ return mNetdListener.registerNetdEventCallback(callback);
+ }
+
+ @Override
+ public boolean unregisterNetdEventCallback() {
+ enforceNetdEventListeningPermission();
+ if (mNetdListener == null) {
+ // if the service is null, we aren't registered anyway
+ return true;
+ }
+ return mNetdListener.unregisterNetdEventCallback();
+ }
};
private static final ToIntFunction<Context> READ_BUFFER_SIZE = (ctx) -> {
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 363d7cb..1625aef 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -20,10 +20,12 @@
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
+import android.net.INetdEventCallback;
import android.net.NetworkRequest;
import android.net.metrics.DnsEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.INetdEventListener;
+import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -119,6 +121,21 @@
}
};
+ // Callback should only be registered/unregistered when logging is being enabled/disabled in DPM
+ // by the device owner. It's DevicePolicyManager's responsibility to ensure that.
+ @GuardedBy("this")
+ private INetdEventCallback mNetdEventCallback;
+
+ public synchronized boolean registerNetdEventCallback(INetdEventCallback callback) {
+ mNetdEventCallback = callback;
+ return true;
+ }
+
+ public synchronized boolean unregisterNetdEventCallback() {
+ mNetdEventCallback = null;
+ return true;
+ }
+
public NetdEventListenerService(Context context) {
this(context.getSystemService(ConnectivityManager.class), new IpConnectivityLog());
}
@@ -136,7 +153,8 @@
// Called concurrently by multiple binder threads.
// This method must not block or perform long-running operations.
public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
- String hostname, String[] ipAddresses, int ipAddressesCount, int uid) {
+ String hostname, String[] ipAddresses, int ipAddressesCount, int uid)
+ throws RemoteException {
maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)",
netId, eventType, returnCode, latencyMs));
@@ -146,14 +164,23 @@
mEventBatches.put(netId, batch);
}
batch.addResult((byte) eventType, (byte) returnCode, latencyMs);
+
+ if (mNetdEventCallback != null) {
+ mNetdEventCallback.onDnsEvent(hostname, ipAddresses, ipAddressesCount,
+ System.currentTimeMillis(), uid);
+ }
}
@Override
// Called concurrently by multiple binder threads.
// This method must not block or perform long-running operations.
public synchronized void onConnectEvent(int netId, int latencyMs, String ipAddr, int port,
- int uid) {
+ int uid) throws RemoteException {
maybeVerboseLog(String.format("onConnectEvent(%d, %d)", netId, latencyMs));
+
+ if (mNetdEventCallback != null) {
+ mNetdEventCallback.onConnectEvent(ipAddr, port, System.currentTimeMillis(), uid);
+ }
}
public synchronized void dump(PrintWriter writer) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1ecb3d3..42b5dc0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -78,8 +78,10 @@
import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
+import android.net.IIpConnectivityMetrics;
import android.net.ProxyInfo;
import android.net.Uri;
+import android.net.metrics.IpConnectivityLog;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
@@ -361,6 +363,7 @@
boolean mIsWatch;
private final SecurityLogMonitor mSecurityLogMonitor;
+ private NetworkLogger mNetworkLogger;
private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
@@ -480,6 +483,16 @@
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
getSendingUserId());
+ /*
+ * Network logging would ideally be started in setDeviceOwnerSystemPropertyLocked(),
+ * however it's too early in the boot process to register with IIpConnectivityMetrics
+ * to listen for events.
+ */
+ if (Intent.ACTION_USER_STARTED.equals(action)
+ && userHandle == mOwners.getDeviceOwnerUserId()
+ && isNetworkLoggingEnabledInternal()) {
+ setNetworkLoggingActiveInternal(true);
+ }
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
&& userHandle == mOwners.getDeviceOwnerUserId()
&& getDeviceOwnerRemoteBugreportUri() != null) {
@@ -551,6 +564,7 @@
private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time";
private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users";
+ private static final String TAG_IS_NETWORK_LOGGING_ENABLED = "is_network_logging_enabled";
private static final String TAG_ACCOUNT_TYPE = "account-type";
private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES
= "permitted-accessiblity-services";
@@ -637,6 +651,7 @@
boolean disableScreenCapture = false; // Can only be set by a device/profile owner.
boolean requireAutoTime = false; // Can only be set by a device owner.
boolean forceEphemeralUsers = false; // Can only be set by a device owner.
+ boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner.
ActiveAdmin parentAdmin;
final boolean isParent;
@@ -853,6 +868,11 @@
out.attribute(null, ATTR_VALUE, Boolean.toString(forceEphemeralUsers));
out.endTag(null, TAG_FORCE_EPHEMERAL_USERS);
}
+ if (isNetworkLoggingEnabled) {
+ out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled));
+ out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
+ }
if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
@@ -1039,6 +1059,9 @@
} else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) {
forceEphemeralUsers = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) {
+ isNetworkLoggingEnabled = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
@@ -1279,6 +1302,8 @@
pw.println(requireAutoTime);
pw.print(prefix); pw.print("forceEphemeralUsers=");
pw.println(forceEphemeralUsers);
+ pw.print(prefix); pw.print("isNetworkLoggingEnabled=");
+ pw.println(isNetworkLoggingEnabled);
pw.print(prefix); pw.print("disabledKeyguardFeatures=");
pw.println(disabledKeyguardFeatures);
pw.print(prefix); pw.print("crossProfileWidgetProviders=");
@@ -1405,6 +1430,11 @@
return mContext.getSystemService(NotificationManager.class);
}
+ IIpConnectivityMetrics getIIpConnectivityMetrics() {
+ return (IIpConnectivityMetrics) IIpConnectivityMetrics.Stub.asInterface(
+ ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+ }
+
PowerManagerInternal getPowerManagerInternal() {
return LocalServices.getService(PowerManagerInternal.class);
}
@@ -9079,6 +9109,13 @@
if (!isDeviceOwnerManagedSingleUserDevice()) {
mInjector.securityLogSetLoggingEnabledProperty(false);
Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device.");
+
+ getDeviceOwnerAdminLocked().isNetworkLoggingEnabled = false;
+ saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ setNetworkLoggingActiveInternal(false);
+ Slog.w(LOG_TAG, "Network logging turned off as it's no longer a single user"
+ + " device.");
+
if (mOwners.hasDeviceOwner()) {
setBackupServiceEnabledInternal(false);
Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user.");
@@ -9463,4 +9500,62 @@
final int callingUid = mInjector.binderGetCallingUid();
return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
}
+
+ @Override
+ public synchronized void setNetworkLoggingEnabled(ComponentName admin, boolean enabled) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(admin);
+ ensureDeviceOwnerManagingSingleUser(admin);
+
+ if (enabled == isNetworkLoggingEnabledInternal()) {
+ // already in the requested state
+ return;
+ }
+ getDeviceOwnerAdminLocked().isNetworkLoggingEnabled = enabled;
+ saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+
+ setNetworkLoggingActiveInternal(enabled);
+ }
+
+ private synchronized void setNetworkLoggingActiveInternal(boolean active) {
+ final long callingIdentity = mInjector.binderClearCallingIdentity();
+ try {
+ if (active) {
+ mNetworkLogger = new NetworkLogger(this, mInjector.getPackageManagerInternal());
+ if (!mNetworkLogger.startNetworkLogging()) {
+ mNetworkLogger = null;
+ Slog.wtf(LOG_TAG, "Network logging could not be started due to the logging"
+ + " service not being available yet.");
+ }
+ } else {
+ if (mNetworkLogger != null && !mNetworkLogger.stopNetworkLogging()) {
+ mNetworkLogger = null;
+ Slog.wtf(LOG_TAG, "Network logging could not be stopped due to the logging"
+ + " service not being available yet.");
+ }
+ mNetworkLogger = null;
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override
+ public boolean isNetworkLoggingEnabled(ComponentName admin) {
+ if (!mHasFeature) {
+ return false;
+ }
+ Preconditions.checkNotNull(admin);
+ synchronized (this) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ return isNetworkLoggingEnabledInternal();
+ }
+ }
+
+ private synchronized boolean isNetworkLoggingEnabledInternal() {
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ return (deviceOwner != null) && deviceOwner.isNetworkLoggingEnabled;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
new file mode 100644
index 0000000..db17ca2
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.content.pm.PackageManagerInternal;
+import android.net.IIpConnectivityMetrics;
+import android.net.INetdEventCallback;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.ServiceThread;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class for managing network logging.
+ * This class is not thread-safe, callers should synchronize access.
+ */
+final class NetworkLogger {
+
+ private static final String TAG = NetworkLogger.class.getSimpleName();
+
+ private final DevicePolicyManagerService mDpm;
+ private final PackageManagerInternal mPm;
+
+ private IIpConnectivityMetrics mIpConnectivityMetrics;
+ private boolean mIsLoggingEnabled;
+
+ private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+ @Override
+ public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
+ long timestamp, int uid) {
+ if (!mIsLoggingEnabled) {
+ return;
+ }
+ // TODO(mkarpinski): send msg with data to Handler
+ }
+
+ @Override
+ public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) {
+ if (!mIsLoggingEnabled) {
+ return;
+ }
+ // TODO(mkarpinski): send msg with data to Handler
+ }
+ };
+
+ NetworkLogger(DevicePolicyManagerService dpm, PackageManagerInternal pm) {
+ mDpm = dpm;
+ mPm = pm;
+ }
+
+ private boolean checkIpConnectivityMetricsService() {
+ if (mIpConnectivityMetrics != null) {
+ return true;
+ }
+ final IIpConnectivityMetrics service = mDpm.mInjector.getIIpConnectivityMetrics();
+ if (service == null) {
+ return false;
+ }
+ mIpConnectivityMetrics = service;
+ return true;
+ }
+
+ boolean startNetworkLogging() {
+ Log.d(TAG, "Starting network logging.");
+ if (!checkIpConnectivityMetricsService()) {
+ // the IIpConnectivityMetrics service should have been present at this point
+ Slog.wtf(TAG, "Failed to register callback with IIpConnectivityMetrics.");
+ return false;
+ }
+ try {
+ if (mIpConnectivityMetrics.registerNetdEventCallback(mNetdEventCallback)) {
+ // TODO(mkarpinski): start a new ServiceThread, instantiate a Handler etc.
+ mIsLoggingEnabled = true;
+ return true;
+ } else {
+ return false;
+ }
+ } catch (RemoteException re) {
+ Slog.wtf(TAG, "Failed to make remote calls to register the callback", re);
+ return false;
+ }
+ }
+
+ boolean stopNetworkLogging() {
+ Log.d(TAG, "Stopping network logging");
+ // stop the logging regardless of whether we failed to unregister listener
+ mIsLoggingEnabled = false;
+ try {
+ if (!checkIpConnectivityMetricsService()) {
+ // the IIpConnectivityMetrics service should have been present at this point
+ Slog.wtf(TAG, "Failed to unregister callback with IIpConnectivityMetrics.");
+ // logging is forcefully disabled even if unregistering fails
+ return true;
+ }
+ return mIpConnectivityMetrics.unregisterNetdEventCallback();
+ } catch (RemoteException re) {
+ Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re);
+ } finally {
+ // TODO(mkarpinski): quitSafely() the Handler
+ return true;
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 9e2fd62..af4a374 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -22,6 +22,7 @@
import android.net.metrics.DnsEvent;
import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
+import android.os.RemoteException;
import junit.framework.TestCase;
import org.junit.Before;
@@ -157,9 +158,13 @@
}
void log(int netId, int[] latencies) {
- for (int l : latencies) {
- mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null, 0,
- 0);
+ try {
+ for (int l : latencies) {
+ mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null,
+ 0, 0);
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}