diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2013-08-27 04:08:54 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-08-27 04:08:54 +0000 |
commit | 703187f76559de7dc98dbd1d24b3558a7ac177eb (patch) | |
tree | 25ef28a279704016b130c5683a276dd1f1ce76da | |
parent | 4e22b851be121ef221c31c5c4fe12b770eb3e812 (diff) | |
parent | 7421a01f18f34d554ca7a9fd987c4f96da2bdf2f (diff) | |
download | frameworks_base-703187f76559de7dc98dbd1d24b3558a7ac177eb.zip frameworks_base-703187f76559de7dc98dbd1d24b3558a7ac177eb.tar.gz frameworks_base-703187f76559de7dc98dbd1d24b3558a7ac177eb.tar.bz2 |
Merge "Add a simple test for NetworkManagementService." into klp-dev
3 files changed, 199 insertions, 6 deletions
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index a9942e3..417d6d8 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -18,6 +18,7 @@ package com.android.server; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.SystemClock; @@ -105,13 +106,24 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo return true; } + private LocalSocketAddress determineSocketAddress() { + // If we're testing, set up a socket in a namespace that's accessible to test code. + // In order to ensure that unprivileged apps aren't able to impersonate native daemons on + // production devices, even if said native daemons ill-advisedly pick a socket name that + // starts with __test__, only allow this on debug builds. + if (mSocket.startsWith("__test__") && Build.IS_DEBUGGABLE) { + return new LocalSocketAddress(mSocket); + } else { + return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); + } + } + private void listenToSocket() throws IOException { LocalSocket socket = null; try { socket = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress(mSocket, - LocalSocketAddress.Namespace.RESERVED); + LocalSocketAddress address = determineSocketAddress(); socket.connect(address); diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 16cfa66..dfcab29 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -95,6 +95,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub private static final String TAG = "NetworkManagementService"; private static final boolean DBG = false; private static final String NETD_TAG = "NetdConnector"; + private static final String NETD_SOCKET_NAME = "netd"; private static final String ADD = "add"; private static final String REMOVE = "remove"; @@ -187,7 +188,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub * * @param context Binder context for this service */ - private NetworkManagementService(Context context) { + private NetworkManagementService(Context context, String socket) { mContext = context; if ("simulator".equals(SystemProperties.get("ro.product.device"))) { @@ -195,15 +196,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub } mConnector = new NativeDaemonConnector( - new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160); + new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160); mThread = new Thread(mConnector, NETD_TAG); // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); } - public static NetworkManagementService create(Context context) throws InterruptedException { - final NetworkManagementService service = new NetworkManagementService(context); + static NetworkManagementService create(Context context, + String socket) throws InterruptedException { + final NetworkManagementService service = new NetworkManagementService(context, socket); final CountDownLatch connectedSignal = service.mConnectedSignal; if (DBG) Slog.d(TAG, "Creating NetworkManagementService"); service.mThread.start(); @@ -213,6 +215,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub return service; } + public static NetworkManagementService create(Context context) throws InterruptedException { + return create(context, NETD_SOCKET_NAME); + } + public void systemReady() { prepareNativeDaemon(); if (DBG) Slog.d(TAG, "Prepared"); diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java new file mode 100644 index 0000000..56dd7c4 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2012 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; + +import android.content.Context; +import android.net.LocalSocket; +import android.net.LocalServerSocket; +import android.os.Binder; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import com.android.server.net.BaseNetworkObserver; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Tests for {@link NetworkManagementService}. + */ +@LargeTest +public class NetworkManagementServiceTest extends AndroidTestCase { + + private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest"; + private NetworkManagementService mNMService; + private LocalServerSocket mServerSocket; + private LocalSocket mSocket; + private OutputStream mOutputStream; + + @Override + public void setUp() throws Exception { + super.setUp(); + // TODO: make this unnecessary. runtest might already make it unnecessary. + System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); + + // Set up a sheltered test environment. + BroadcastInterceptingContext context = new BroadcastInterceptingContext(getContext()); + mServerSocket = new LocalServerSocket(SOCKET_NAME); + + // Start the service and wait until it connects to our socket. + mNMService = NetworkManagementService.create(context, SOCKET_NAME); + mSocket = mServerSocket.accept(); + mOutputStream = mSocket.getOutputStream(); + } + + @Override + public void tearDown() throws Exception { + if (mSocket != null) mSocket.close(); + if (mServerSocket != null) mServerSocket.close(); + super.tearDown(); + } + + /** + * Sends a message on the netd socket and gives the events some time to make it back. + */ + private void sendMessage(String message) throws IOException { + // Strings are null-terminated, so add "\0" at the end. + mOutputStream.write((message + "\0").getBytes()); + } + + private static <T> T expectSoon(T mock) { + return verify(mock, timeout(100)); + } + + /** + * Tests that network observers work properly. + */ + public void testNetworkObservers() throws Exception { + BaseNetworkObserver observer = mock(BaseNetworkObserver.class); + doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver. + mNMService.registerObserver(observer); + + // Forget everything that happened to the mock so far, so we can explicitly verify + // everything that happens and does not happen to it from now on. + reset(observer); + + // Now send NetworkManagementService messages and ensure that the observer methods are + // called. After every valid message we expect a callback soon after; to ensure that + // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end. + + /** + * Interface changes. + */ + sendMessage("600 Iface added rmnet12"); + expectSoon(observer).interfaceAdded("rmnet12"); + + sendMessage("600 Iface removed eth1"); + expectSoon(observer).interfaceRemoved("eth1"); + + sendMessage("607 Iface removed eth1"); + // Invalid code. + + sendMessage("600 Iface borked lo down"); + // Invalid event. + + sendMessage("600 Iface changed clat4 up again"); + // Extra tokens. + + sendMessage("600 Iface changed clat4 up"); + expectSoon(observer).interfaceStatusChanged("clat4", true); + + sendMessage("600 Iface linkstate rmnet0 down"); + expectSoon(observer).interfaceLinkStateChanged("rmnet0", false); + + sendMessage("600 IFACE linkstate clat4 up"); + // Invalid group. + + /** + * Bandwidth control events. + */ + sendMessage("601 limit alert data rmnet_usb0"); + expectSoon(observer).limitReached("data", "rmnet_usb0"); + + sendMessage("601 invalid alert data rmnet0"); + // Invalid group. + + sendMessage("601 limit increased data rmnet0"); + // Invalid event. + + + /** + * Interface class activity. + */ + sendMessage("613 IfaceClass active rmnet0"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true); + + sendMessage("613 IfaceClass idle eth0"); + expectSoon(observer).interfaceClassDataActivityChanged("eth0", false); + + sendMessage("613 IfaceClass reallyactive rmnet0"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", false); + + sendMessage("613 InterfaceClass reallyactive rmnet0"); + // Invalid group. + + + /** + * IP address changes. + */ + sendMessage("614 Address updated fe80::1/64 wlan0 128 253"); + expectSoon(observer).addressUpdated("fe80::1/64", "wlan0", 128, 253); + + // There is no "added". + sendMessage("614 Address added fe80::1/64 wlan0 128 253"); + expectSoon(observer).addressRemoved("fe80::1/64", "wlan0", 128, 253); + + sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); + expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0); + + sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); + // Invalid code. + + // Make sure nothing else was called. + verifyNoMoreInteractions(observer); + } +} |