Tests for SharedMemory
Test: this
Change-Id: I414614c25b015d1bcbf1364f94615034488be84f
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index ccc72a1..bf6f2fe 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -39,7 +39,8 @@
src/android/os/cts/IParcelFileDescriptorPeer.aidl \
src/android/os/cts/IEmptyService.aidl \
src/android/os/cts/ISeccompIsolatedService.aidl \
- src/android/os/cts/ISecondary.aidl
+ src/android/os/cts/ISecondary.aidl \
+ src/android/os/cts/ISharedMemoryService.aidl
LOCAL_PACKAGE_NAME := CtsOsTestCases
diff --git a/tests/tests/os/AndroidManifest.xml b/tests/tests/os/AndroidManifest.xml
index 846251f..a227cc3 100644
--- a/tests/tests/os/AndroidManifest.xml
+++ b/tests/tests/os/AndroidManifest.xml
@@ -76,6 +76,10 @@
android:name="android.os.cts.CrossProcessExceptionService"
android:process=":green"
android:exported="true" />
+ <service
+ android:name="android.os.cts.SharedMemoryService"
+ android:process=":sharedmem"
+ android:exported="false" />
<service android:name="android.os.cts.LocalService">
<intent-filter>
diff --git a/tests/tests/os/src/android/os/cts/ISharedMemoryService.aidl b/tests/tests/os/src/android/os/cts/ISharedMemoryService.aidl
new file mode 100644
index 0000000..651c62a
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/ISharedMemoryService.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.os.cts;
+
+import android.os.SharedMemory;
+
+interface ISharedMemoryService {
+ void setup(in SharedMemory memory, int prot);
+ byte read(int index);
+ void write(int index, byte value);
+}
diff --git a/tests/tests/os/src/android/os/cts/MemoryFileTest.java b/tests/tests/os/src/android/os/cts/MemoryFileTest.java
index def73b2..6e6eba8 100644
--- a/tests/tests/os/src/android/os/cts/MemoryFileTest.java
+++ b/tests/tests/os/src/android/os/cts/MemoryFileTest.java
@@ -56,7 +56,7 @@
byte[] data = new byte[512];
mMemoryFile.writeBytes(data, srcOffset, destOffset, count);
fail("MemoryFile should throw IndexOutOfBoundsException here.");
- } catch (IndexOutOfBoundsException e) {
+ } catch (IndexOutOfBoundsException | IllegalArgumentException e) {
// expected
}
}
@@ -101,13 +101,10 @@
mMemoryFile = new MemoryFile("Test File", 512);
assertEquals(512, mMemoryFile.length());
- mMemoryFile = new MemoryFile("Test File", 0);
- assertEquals(0, mMemoryFile.length());
-
try {
mMemoryFile = new MemoryFile("Test File", -512);
fail();
- } catch (IOException expected) {
+ } catch (IOException | IllegalArgumentException expected) {
}
}
@@ -142,7 +139,7 @@
byte[] data = new byte[512];
mMemoryFile.readBytes(data, srcOffset, destOffset, count);
fail("MemoryFile should throw IndexOutOfBoundsException here.");
- } catch (IndexOutOfBoundsException e) {
+ } catch (IndexOutOfBoundsException | IllegalArgumentException e) {
// expected
}
}
diff --git a/tests/tests/os/src/android/os/cts/SharedMemoryService.java b/tests/tests/os/src/android/os/cts/SharedMemoryService.java
new file mode 100644
index 0000000..fcc38d5
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/SharedMemoryService.java
@@ -0,0 +1,66 @@
+/*
+ * 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.os.cts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+
+import java.nio.ByteBuffer;
+
+public class SharedMemoryService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new SharedMemoryServiceImpl();
+ }
+
+ private static class SharedMemoryServiceImpl extends ISharedMemoryService.Stub {
+ private SharedMemory mSharedMemory;
+ private ByteBuffer mMappedBuffer;
+
+ @Override
+ public void setup(SharedMemory memory, int prot) throws RemoteException {
+ mSharedMemory = memory;
+ try {
+ mMappedBuffer = mSharedMemory.map(prot, 0, mSharedMemory.getSize());
+ } catch (ErrnoException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public byte read(int index) throws RemoteException {
+ // Although we expect only one client we need to insert memory barriers to ensure
+ // visibility
+ synchronized (mMappedBuffer) {
+ return mMappedBuffer.get(index);
+ }
+ }
+
+ @Override
+ public void write(int index, byte value) throws RemoteException {
+ // Although we expect only one client we need to insert memory barriers to ensure
+ // visibility
+ synchronized (mMappedBuffer) {
+ mMappedBuffer.put(index, value);
+ }
+ }
+ }
+}
diff --git a/tests/tests/os/src/android/os/cts/SharedMemoryTest.java b/tests/tests/os/src/android/os/cts/SharedMemoryTest.java
new file mode 100644
index 0000000..c40cdc8
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/SharedMemoryTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.os.cts;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static android.system.OsConstants.PROT_READ;
+import static android.system.OsConstants.PROT_WRITE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SharedMemory;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+
+import com.google.common.util.concurrent.AbstractFuture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SharedMemoryTest {
+
+ private Instrumentation mInstrumentation;
+ private Intent mRemoteIntent;
+ private PeerConnection mRemoteConnection;
+ private ISharedMemoryService mRemote;
+
+ public static class PeerConnection extends AbstractFuture<ISharedMemoryService>
+ implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ set(ISharedMemoryService.Stub.asInterface(service));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+
+ @Override
+ public ISharedMemoryService get() throws InterruptedException, ExecutionException {
+ try {
+ return get(5, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ final Context context = mInstrumentation.getContext();
+ // Bring up both remote processes and wire them to each other
+ mRemoteIntent = new Intent();
+ mRemoteIntent.setComponent(new ComponentName(
+ "android.os.cts", "android.os.cts.SharedMemoryService"));
+ mRemoteConnection = new PeerConnection();
+ getContext().bindService(mRemoteIntent, mRemoteConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+ mRemote = mRemoteConnection.get();
+ }
+
+ @After
+ public void tearDown() {
+ final Context context = mInstrumentation.getContext();
+ context.unbindService(mRemoteConnection);
+ }
+
+ @Test
+ public void testReadWrite() throws RemoteException, ErrnoException {
+ try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+ ByteBuffer buffer = sharedMemory.mapReadWrite();
+ mRemote.setup(sharedMemory, PROT_READ | PROT_WRITE);
+
+ byte expected = 5;
+ buffer.put(0, expected);
+ assertEquals(expected, buffer.get(0));
+ // Memory barrier
+ synchronized (sharedMemory) {}
+ assertEquals(expected, mRemote.read(0));
+ expected = 10;
+ mRemote.write(0, expected);
+ // Memory barrier
+ synchronized (sharedMemory) {}
+ assertEquals(expected, buffer.get(0));
+ SharedMemory.unmap(buffer);
+ }
+ }
+
+ @Test
+ public void testReadOnly() throws RemoteException, ErrnoException {
+ try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+ ByteBuffer buffer = sharedMemory.mapReadWrite();
+ sharedMemory.setProtect(PROT_READ);
+ mRemote.setup(sharedMemory, PROT_READ);
+
+ byte expected = 15;
+ buffer.put(0, expected);
+ assertEquals(expected, buffer.get(0));
+ // Memory barrier
+ synchronized (sharedMemory) {}
+ assertEquals(expected, mRemote.read(0));
+ expected = 20;
+ try {
+ mRemote.write(0, expected);
+ fail("write shouldn't have worked, should be read only");
+ } catch (Exception e) {}
+
+ buffer.put(0, expected);
+ assertEquals(expected, buffer.get(0));
+ // Memory barrier
+ synchronized (sharedMemory) {}
+ assertEquals(expected, mRemote.read(0));
+ }
+ }
+
+ @Test
+ public void testUseAfterClose() throws RemoteException, ErrnoException {
+ ByteBuffer buffer;
+ try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+ buffer = sharedMemory.mapReadWrite();
+ mRemote.setup(sharedMemory, PROT_READ | PROT_WRITE);
+ }
+ byte expected = 5;
+ buffer.put(0, expected);
+ assertEquals(expected, buffer.get(0));
+ // Memory barrier
+ synchronized (buffer) {}
+ assertEquals(expected, mRemote.read(0));
+ expected = 10;
+ mRemote.write(0, expected);
+ // Memory barrier
+ synchronized (buffer) {}
+ assertEquals(expected, buffer.get(0));
+ SharedMemory.unmap(buffer);
+ }
+
+ @Test
+ public void testGetFd() throws ErrnoException {
+ SharedMemory sharedMemory = SharedMemory.create("hello", 1024);
+ assertNotEquals(-1, sharedMemory.getFd());
+ assertNotNull(sharedMemory.getFileDescriptor());
+ assertTrue(sharedMemory.getFileDescriptor().valid());
+ sharedMemory.close();
+ assertEquals(-1, sharedMemory.getFd());
+ assertNotNull(sharedMemory.getFileDescriptor());
+ assertTrue(!sharedMemory.getFileDescriptor().valid());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testInvalidCreate() throws ErrnoException {
+ SharedMemory.create(null, -1);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testInvalidMapProt() throws ErrnoException {
+ try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+ sharedMemory.map(-1, 0, 1);
+ }
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testInvalidSetProt() throws ErrnoException {
+ try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+ sharedMemory.setProtect(-1);
+ }
+ }
+
+ @Test
+ public void testSetProtAddProt() throws ErrnoException {
+ try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+ assertTrue(sharedMemory.setProtect(OsConstants.PROT_READ));
+ assertTrue(sharedMemory.setProtect(OsConstants.PROT_READ));
+ assertFalse(sharedMemory.setProtect(OsConstants.PROT_READ | OsConstants.PROT_WRITE));
+ assertTrue(sharedMemory.setProtect(OsConstants.PROT_NONE));
+ assertFalse(sharedMemory.setProtect(OsConstants.PROT_READ));
+ }
+ }
+
+ @Test(expected=IllegalStateException.class)
+ public void testMapAfterClose() throws ErrnoException {
+ SharedMemory sharedMemory = SharedMemory.create(null, 1);
+ sharedMemory.close();
+ sharedMemory.mapReadWrite();
+ }
+
+ @Test(expected=ReadOnlyBufferException.class)
+ public void testWriteToReadOnly() throws ErrnoException {
+ try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) {
+ sharedMemory.setProtect(PROT_READ);
+ ByteBuffer buffer = null;
+ try {
+ buffer = sharedMemory.mapReadWrite();
+ fail("Should have thrown an exception");
+ } catch (ErrnoException ex) {
+ assertEquals(OsConstants.EPERM, ex.errno);
+ }
+ buffer = sharedMemory.mapReadOnly();
+ assertTrue(buffer.isReadOnly());
+ buffer.put(0, (byte) 0);
+ }
+ }
+}