1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.os.cts; 18 19 import static android.system.OsConstants.PROT_READ; 20 import static android.system.OsConstants.PROT_WRITE; 21 22 import static androidx.test.InstrumentationRegistry.getContext; 23 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertFalse; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 import android.app.Instrumentation; 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.ServiceConnection; 34 import android.os.IBinder; 35 import android.os.RemoteException; 36 import android.os.SharedMemory; 37 import android.system.ErrnoException; 38 import android.system.OsConstants; 39 40 import androidx.test.InstrumentationRegistry; 41 import androidx.test.filters.MediumTest; 42 import androidx.test.runner.AndroidJUnit4; 43 44 import com.google.common.util.concurrent.AbstractFuture; 45 46 import org.junit.After; 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 51 import java.nio.ByteBuffer; 52 import java.nio.ReadOnlyBufferException; 53 import java.util.concurrent.ExecutionException; 54 import java.util.concurrent.TimeUnit; 55 import java.util.concurrent.TimeoutException; 56 57 @MediumTest 58 @RunWith(AndroidJUnit4.class) 59 public class SharedMemoryTest { 60 61 static { 62 System.loadLibrary("ctsos_jni"); 63 } 64 65 private Instrumentation mInstrumentation; 66 private Intent mRemoteIntent; 67 private PeerConnection mRemoteConnection; 68 private ISharedMemoryService mRemote; 69 70 public static class PeerConnection extends AbstractFuture<ISharedMemoryService> 71 implements ServiceConnection { 72 @Override 73 public void onServiceConnected(ComponentName name, IBinder service) { 74 set(ISharedMemoryService.Stub.asInterface(service)); 75 } 76 77 @Override 78 public void onServiceDisconnected(ComponentName name) { 79 } 80 81 @Override 82 public ISharedMemoryService get() throws InterruptedException, ExecutionException { 83 try { 84 return get(5, TimeUnit.SECONDS); 85 } catch (TimeoutException e) { 86 throw new RuntimeException(e); 87 } 88 } 89 } 90 91 @Before 92 public void setUp() throws Exception { 93 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 94 final Context context = mInstrumentation.getContext(); 95 // Bring up both remote processes and wire them to each other 96 mRemoteIntent = new Intent(); 97 mRemoteIntent.setComponent(new ComponentName( 98 "android.os.cts", "android.os.cts.SharedMemoryService")); 99 mRemoteConnection = new PeerConnection(); 100 getContext().bindService(mRemoteIntent, mRemoteConnection, 101 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT); 102 mRemote = mRemoteConnection.get(); 103 } 104 105 @After 106 public void tearDown() { 107 final Context context = mInstrumentation.getContext(); 108 context.unbindService(mRemoteConnection); 109 } 110 111 @Test 112 public void testReadWrite() throws RemoteException, ErrnoException { 113 try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) { 114 ByteBuffer buffer = sharedMemory.mapReadWrite(); 115 mRemote.setup(sharedMemory, PROT_READ | PROT_WRITE); 116 117 byte expected = 5; 118 buffer.put(0, expected); 119 assertEquals(expected, buffer.get(0)); 120 // Memory barrier 121 synchronized (sharedMemory) {} 122 assertEquals(expected, mRemote.read(0)); 123 expected = 10; 124 mRemote.write(0, expected); 125 // Memory barrier 126 synchronized (sharedMemory) {} 127 assertEquals(expected, buffer.get(0)); 128 SharedMemory.unmap(buffer); 129 } 130 } 131 132 @Test 133 public void testReadOnly() throws RemoteException, ErrnoException { 134 try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) { 135 ByteBuffer buffer = sharedMemory.mapReadWrite(); 136 sharedMemory.setProtect(PROT_READ); 137 mRemote.setup(sharedMemory, PROT_READ); 138 139 byte expected = 15; 140 buffer.put(0, expected); 141 assertEquals(expected, buffer.get(0)); 142 // Memory barrier 143 synchronized (sharedMemory) {} 144 assertEquals(expected, mRemote.read(0)); 145 expected = 20; 146 try { 147 mRemote.write(0, expected); 148 fail("write shouldn't have worked, should be read only"); 149 } catch (Exception e) {} 150 151 buffer.put(0, expected); 152 assertEquals(expected, buffer.get(0)); 153 // Memory barrier 154 synchronized (sharedMemory) {} 155 assertEquals(expected, mRemote.read(0)); 156 } 157 } 158 159 @Test 160 public void testUseAfterClose() throws RemoteException, ErrnoException { 161 ByteBuffer buffer; 162 try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) { 163 buffer = sharedMemory.mapReadWrite(); 164 mRemote.setup(sharedMemory, PROT_READ | PROT_WRITE); 165 } 166 byte expected = 5; 167 buffer.put(0, expected); 168 assertEquals(expected, buffer.get(0)); 169 // Memory barrier 170 synchronized (buffer) {} 171 assertEquals(expected, mRemote.read(0)); 172 expected = 10; 173 mRemote.write(0, expected); 174 // Memory barrier 175 synchronized (buffer) {} 176 assertEquals(expected, buffer.get(0)); 177 SharedMemory.unmap(buffer); 178 } 179 180 @Test 181 public void testUseAfterUnmap() throws RemoteException, ErrnoException { 182 SharedMemory sharedMemory = SharedMemory.create(null, 1); 183 ByteBuffer buffer = sharedMemory.mapReadWrite(); 184 byte expected = 5; 185 buffer.put(0, expected); 186 assertEquals(expected, buffer.get(0)); 187 SharedMemory.unmap(buffer); 188 boolean failed = false; 189 try { 190 buffer.get(0); 191 failed = true; 192 } catch (Throwable t) { } 193 assertFalse(failed); 194 } 195 196 private static native boolean nWriteByte(SharedMemory memory, int index, byte value); 197 198 @Test 199 public void testNdkInterop() throws ErrnoException { 200 SharedMemory sharedMemory = SharedMemory.create("hello", 1024); 201 ByteBuffer buffer = sharedMemory.mapReadWrite(); 202 assertEquals(0, buffer.get(0)); 203 assertTrue(nWriteByte(sharedMemory, 0, (byte) 1)); 204 assertEquals(1, buffer.get(0)); 205 sharedMemory.close(); 206 buffer.put(0, (byte) 5); 207 assertFalse(nWriteByte(sharedMemory, 0, (byte) 2)); 208 assertEquals(5, buffer.get(0)); 209 } 210 211 @Test(expected=IllegalArgumentException.class) 212 public void testInvalidCreate() throws ErrnoException { 213 SharedMemory.create(null, -1); 214 } 215 216 @Test(expected=IllegalArgumentException.class) 217 public void testInvalidMapProt() throws ErrnoException { 218 try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) { 219 sharedMemory.map(-1, 0, 1); 220 } 221 } 222 223 @Test(expected=IllegalArgumentException.class) 224 public void testInvalidSetProt() throws ErrnoException { 225 try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) { 226 sharedMemory.setProtect(-1); 227 } 228 } 229 230 @Test 231 public void testSetProtAddProt() throws ErrnoException { 232 try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) { 233 assertTrue(sharedMemory.setProtect(OsConstants.PROT_READ)); 234 assertTrue(sharedMemory.setProtect(OsConstants.PROT_READ)); 235 assertFalse(sharedMemory.setProtect(OsConstants.PROT_READ | OsConstants.PROT_WRITE)); 236 assertTrue(sharedMemory.setProtect(OsConstants.PROT_NONE)); 237 assertFalse(sharedMemory.setProtect(OsConstants.PROT_READ)); 238 } 239 } 240 241 @Test(expected=IllegalStateException.class) 242 public void testMapAfterClose() throws ErrnoException { 243 SharedMemory sharedMemory = SharedMemory.create(null, 1); 244 sharedMemory.close(); 245 sharedMemory.mapReadWrite(); 246 } 247 248 @Test(expected=ReadOnlyBufferException.class) 249 public void testWriteToReadOnly() throws ErrnoException { 250 try (SharedMemory sharedMemory = SharedMemory.create(null, 1)) { 251 sharedMemory.setProtect(PROT_READ); 252 ByteBuffer buffer = null; 253 try { 254 buffer = sharedMemory.mapReadWrite(); 255 fail("Should have thrown an exception"); 256 } catch (ErrnoException ex) { 257 assertEquals(OsConstants.EPERM, ex.errno); 258 } 259 buffer = sharedMemory.mapReadOnly(); 260 assertTrue(buffer.isReadOnly()); 261 buffer.put(0, (byte) 0); 262 } 263 } 264 } 265