• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 com.android.internal.os;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.fail;
24 import static org.junit.Assume.assumeTrue;
25 
26 import android.platform.test.annotations.Presubmit;
27 
28 import androidx.test.filters.SmallTest;
29 
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.junit.runner.RunWith;
33 import org.junit.runners.JUnit4;
34 
35 import java.io.FileDescriptor;
36 import java.io.IOException;
37 
38 /** Tests for {@link TimeoutRecord}. */
39 @SmallTest
40 @Presubmit
41 @RunWith(JUnit4.class)
42 public class ApplicationSharedMemoryTest {
43 
44     @Before
setUp()45     public void setUp() {
46         // Skip tests if the feature under test is disabled.
47         assumeTrue(Flags.applicationSharedMemoryEnabled());
48     }
49 
50     /**
51      * Every application process, including ours, should have had an instance installed at this
52      * point.
53      */
54     @Test
hasInstance()55     public void hasInstance() {
56         // This shouldn't throw and shouldn't return null.
57         assertNotNull(ApplicationSharedMemory.getInstance());
58     }
59 
60     /** Any app process should be able to read shared memory values. */
61     @Test
canRead()62     public void canRead() {
63         ApplicationSharedMemory instance = ApplicationSharedMemory.getInstance();
64         try {
65             instance.getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis();
66             // Don't actually care about the value of the above.
67         } catch (java.time.DateTimeException e) {
68             // This exception is okay during testing.  It means there was no time source, which
69             // could be because of network problems or a feature being flagged off.
70         }
71     }
72 
73     /** Application processes should not have mutable access. */
74     @Test
appInstanceNotMutable()75     public void appInstanceNotMutable() {
76         ApplicationSharedMemory instance = ApplicationSharedMemory.getInstance();
77         try {
78             instance.setLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(17);
79             fail("Attempted mutation in an app process should throw");
80             instance.writeSystemFeaturesCache(new int[] {1, 2, 3, 4, 5});
81             fail("Attempted feature mutation in an app process should throw");
82         } catch (Exception expected) {
83         }
84     }
85 
86     /** Instances share memory if they share the underlying memory region. */
87     @Test
instancesShareMemory()88     public void instancesShareMemory() throws IOException {
89         ApplicationSharedMemory instance1 = ApplicationSharedMemory.create();
90         ApplicationSharedMemory instance2 =
91                 ApplicationSharedMemory.fromFileDescriptor(
92                         instance1.getFileDescriptor(), /* mutable= */ true);
93         ApplicationSharedMemory instance3 =
94                 ApplicationSharedMemory.fromFileDescriptor(
95                         instance2.getReadOnlyFileDescriptor(), /* mutable= */ false);
96 
97         instance1.setLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(17);
98         assertEquals(
99                 17, instance1.getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis());
100         assertEquals(
101                 17, instance2.getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis());
102         assertEquals(
103                 17, instance3.getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis());
104 
105         instance2.setLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(24);
106         assertEquals(
107                 24, instance1.getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis());
108         assertEquals(
109                 24, instance2.getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis());
110         assertEquals(
111                 24, instance3.getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis());
112     }
113 
114     /** Can't map read-only memory as mutable. */
115     @Test
readOnlyCantBeMutable()116     public void readOnlyCantBeMutable() throws IOException {
117         ApplicationSharedMemory readWriteInstance = ApplicationSharedMemory.create();
118         FileDescriptor readOnlyFileDescriptor = readWriteInstance.getReadOnlyFileDescriptor();
119 
120         try {
121             ApplicationSharedMemory.fromFileDescriptor(readOnlyFileDescriptor, /* mutable= */ true);
122             fail("Shouldn't be able to map read-only memory as mutable");
123         } catch (Exception expected) {
124         }
125     }
126 
127     /** If system feature caching is enabled, it should be auto-written into app shared memory. */
128     @Test
canReadSystemFeatures()129     public void canReadSystemFeatures() throws IOException {
130         assumeTrue(android.content.pm.Flags.cacheSdkSystemFeatures());
131         ApplicationSharedMemory instance = ApplicationSharedMemory.getInstance();
132         assertThat(instance.readSystemFeaturesCache()).isNotEmpty();
133     }
134 
135     @Test
systemFeaturesShareMemory()136     public void systemFeaturesShareMemory() throws IOException {
137         ApplicationSharedMemory instance1 = ApplicationSharedMemory.create();
138 
139         int[] featureVersions = new int[] {1, 2, 3, 4, 5};
140         instance1.writeSystemFeaturesCache(featureVersions);
141         assertThat(featureVersions).isEqualTo(instance1.readSystemFeaturesCache());
142 
143         ApplicationSharedMemory instance2 =
144                 ApplicationSharedMemory.fromFileDescriptor(
145                         instance1.getReadOnlyFileDescriptor(), /* mutable= */ false);
146         assertThat(featureVersions).isEqualTo(instance2.readSystemFeaturesCache());
147     }
148 
149     @Test
systemFeaturesAreWriteOnce()150     public void systemFeaturesAreWriteOnce() throws IOException {
151         ApplicationSharedMemory instance1 = ApplicationSharedMemory.create();
152 
153         try {
154             instance1.writeSystemFeaturesCache(new int[5000]);
155             fail("Cannot write an overly large system feature version buffer.");
156         } catch (IllegalArgumentException expected) {
157         }
158 
159         int[] featureVersions = new int[] {1, 2, 3, 4, 5};
160         instance1.writeSystemFeaturesCache(featureVersions);
161 
162         int[] newFeatureVersions = new int[] {1, 2, 3, 4, 5, 6, 7};
163         try {
164             instance1.writeSystemFeaturesCache(newFeatureVersions);
165             fail("Cannot update system features after first write.");
166         } catch (IllegalStateException expected) {
167         }
168 
169         ApplicationSharedMemory instance2 =
170                 ApplicationSharedMemory.fromFileDescriptor(
171                         instance1.getReadOnlyFileDescriptor(), /* mutable= */ false);
172         try {
173             instance2.writeSystemFeaturesCache(newFeatureVersions);
174             fail("Cannot update system features for read-only ashmem.");
175         } catch (IllegalStateException expected) {
176         }
177     }
178 }
179