Home | History | Annotate | Download | only in cts
      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