1 /*
2  * Copyright (C) 2020 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.sensorratepermission.cts.directreportapi30;
18 
19 import android.content.Context;
20 import android.hardware.HardwareBuffer;
21 import android.hardware.Sensor;
22 import android.hardware.SensorDirectChannel;
23 import android.hardware.SensorManager;
24 import android.hardware.SensorPrivacyManager;
25 import android.hardware.cts.SensorDirectReportTest;
26 import android.hardware.cts.helpers.SensorCtsHelper;
27 import android.hardware.cts.helpers.SensorRatePermissionDirectReportTestHelper;
28 import android.os.SystemClock;
29 import android.os.UserHandle;
30 
31 import androidx.test.platform.app.InstrumentationRegistry;
32 
33 import org.junit.After;
34 import org.junit.Assert;
35 import org.junit.Assume;
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.junit.runners.Parameterized;
40 
41 import java.util.Collection;
42 import java.util.List;
43 import java.util.concurrent.TimeUnit;
44 
45 /**
46  * Test sampling rate obtained by direct connections when:
47  * - The mic toggle is on and off
48  * - App targets API 30
49  *
50  * Expected behaviors:
51  * - Sampling rate is capped when the toggle is on
52  * - Sampling rate is not capped when the toggle is off
53  */
54 @RunWith(Parameterized.class)
55 public class DirectReportAPI30Test {
56     private static SensorRatePermissionDirectReportTestHelper mDirectReportTestHelper;
57     private static SensorPrivacyManager mSensorPrivacyManager;
58     private static SensorManager mSensorManager;
59     private static int mUserID;
60     private final int sensorType;
61 
DirectReportAPI30Test(int sensorType)62     public DirectReportAPI30Test(int sensorType) {
63         this.sensorType = sensorType;
64     }
65 
66     @Parameterized.Parameters
cappedSensorTypeSet()67     public static Collection cappedSensorTypeSet() {
68         return SensorRatePermissionDirectReportTestHelper.CAPPED_SENSOR_TYPE_SET;
69     }
70 
71     @Before
setUp()72     public void setUp() {
73         Context context = InstrumentationRegistry.getInstrumentation().getContext();
74         mDirectReportTestHelper = new SensorRatePermissionDirectReportTestHelper(context,
75                 sensorType);
76         Assume.assumeTrue("Failed to create mDirectReportTestHelper!",
77                 mDirectReportTestHelper != null);
78 
79         mSensorManager = context.getSystemService(SensorManager.class);
80         mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
81         Assume.assumeTrue(mSensorPrivacyManager
82                 .supportsSensorToggle(SensorPrivacyManager.Sensors.MICROPHONE));
83         mUserID = UserHandle.myUserId();
84     }
85 
86     @After
tearDown()87     public void tearDown() throws InterruptedException {
88         if (mDirectReportTestHelper != null) {
89             mDirectReportTestHelper.flipAndAssertMicToggleOff(mUserID, mSensorPrivacyManager);
90         }
91     }
92 
93     @Test
testSamplingRateMicToggleOff()94     public void testSamplingRateMicToggleOff() throws InterruptedException {
95         // Only run this test if we know for sure that the highest direct report rate level of
96         // corresponds to a sampling rate of > 200 Hz
97         if (mDirectReportTestHelper.getSensor().getHighestDirectReportRateLevel()
98                 <= SensorDirectChannel.RATE_FAST) {
99             return;
100         }
101 
102         mDirectReportTestHelper.flipAndAssertMicToggleOff(mUserID, mSensorPrivacyManager);
103         List<SensorDirectReportTest.DirectReportSensorEvent> events =
104                 mDirectReportTestHelper.getSensorEvents(SensorDirectChannel.RATE_VERY_FAST);
105 
106         double obtainedRate = SensorRatePermissionDirectReportTestHelper.computeAvgRate(events,
107                 Long.MIN_VALUE, Long.MAX_VALUE);
108 
109         Assert.assertTrue(mDirectReportTestHelper.errorWhenBelowExpectedRate(),
110                 obtainedRate > SensorRatePermissionDirectReportTestHelper.CAPPED_SAMPLE_RATE_HZ);
111     }
112 
113     @Test
testSamplingRateMicToggleOn()114     public void testSamplingRateMicToggleOn() throws InterruptedException {
115         mDirectReportTestHelper.flipAndAssertMicToggleOn(mUserID, mSensorPrivacyManager);
116         List<SensorDirectReportTest.DirectReportSensorEvent> events =
117                 mDirectReportTestHelper.getSensorEvents(SensorDirectChannel.RATE_VERY_FAST);
118 
119         double obtainedRate = SensorRatePermissionDirectReportTestHelper.computeAvgRate(events,
120                 Long.MIN_VALUE, Long.MAX_VALUE);
121 
122         Assert.assertTrue(mDirectReportTestHelper.errorWhenExceedCappedRate(),
123                 obtainedRate <= SensorRatePermissionDirectReportTestHelper.CAPPED_SAMPLE_RATE_HZ);
124     }
125 
126     /**
127      * Test the case where a connection is ongoing while the mic toggle changes its state:
128      * off -> on -> off. This test is to show that the sensor service is able to cap/uncap the
129      * rate of ongoing direct sensor connections when the state of the mic toggle changes.
130      */
131     @Test
testSamplingRateMicToggleOffOnOff()132     public void testSamplingRateMicToggleOffOnOff() throws InterruptedException {
133         // Only run this test if we know for sure that the highest direct report rate level of
134         // the sensor corresponds to a sampling rate of > 200 Hz and that the sensor supports
135         // direct channel.
136         Sensor s = mDirectReportTestHelper.getSensor();
137         if (s.getHighestDirectReportRateLevel() <= SensorDirectChannel.RATE_FAST
138                 || !s.isDirectChannelTypeSupported(SensorDirectChannel.TYPE_HARDWARE_BUFFER)) {
139             return;
140         }
141         // Start with the mic toggle off
142         mDirectReportTestHelper.flipAndAssertMicToggleOff(mUserID, mSensorPrivacyManager);
143 
144         // Configure a direct channel.
145         int sensorEventCount = 5500; // 800 Hz * 2.5s  + 200 Hz * 2.5s + extra
146         int sharedMemorySize = sensorEventCount *
147                 SensorRatePermissionDirectReportTestHelper.SENSORS_EVENT_SIZE;
148         HardwareBuffer hardwareBuffer = HardwareBuffer.create(
149                 sharedMemorySize, 1, HardwareBuffer.BLOB, 1,
150                 HardwareBuffer.USAGE_CPU_READ_OFTEN | HardwareBuffer.USAGE_GPU_DATA_BUFFER
151                         | HardwareBuffer.USAGE_SENSOR_DIRECT_DATA);
152         SensorDirectChannel channel = mSensorManager.createDirectChannel(hardwareBuffer);
153         int token = channel.configure(s, SensorDirectChannel.RATE_VERY_FAST);
154 
155         // Flip the mic toggle on
156         mDirectReportTestHelper.flipAndAssertMicToggleOn(mUserID, mSensorPrivacyManager);
157         long startMicToggleOn = SystemClock.elapsedRealtimeNanos();
158         SensorCtsHelper.sleep(
159                 SensorRatePermissionDirectReportTestHelper.TEST_RUN_TIME_PERIOD_MILLISEC / 2,
160                 TimeUnit.MILLISECONDS);
161         long endMicToggleOn = SystemClock.elapsedRealtimeNanos();
162 
163         // Flip the mic toggle off
164         mDirectReportTestHelper.flipAndAssertMicToggleOff(mUserID, mSensorPrivacyManager);
165         long startMicToggleOff = SystemClock.elapsedRealtimeNanos();
166         SensorCtsHelper.sleep(
167                 SensorRatePermissionDirectReportTestHelper.TEST_RUN_TIME_PERIOD_MILLISEC / 2,
168                 TimeUnit.MILLISECONDS);
169 
170         // Read the sensor events out
171         channel.configure(s, SensorDirectChannel.RATE_STOP);
172         List<SensorDirectReportTest.DirectReportSensorEvent> events =
173                 mDirectReportTestHelper.readEventsFromHardwareBuffer(token,
174                         hardwareBuffer, sensorEventCount);
175         channel.close();
176         hardwareBuffer.close();
177 
178         // Check the sampling rates when the mic toggle were on and off
179         double rateWhenMicToggleOn =
180                 SensorRatePermissionDirectReportTestHelper.computeAvgRate(events,
181                         startMicToggleOn, endMicToggleOn);
182         Assert.assertTrue(mDirectReportTestHelper.errorWhenExceedCappedRate(),
183                 rateWhenMicToggleOn
184                         <= SensorRatePermissionDirectReportTestHelper.CAPPED_SAMPLE_RATE_HZ);
185 
186         double rateWhenMicToggleOff = SensorRatePermissionDirectReportTestHelper.computeAvgRate(
187                 events, startMicToggleOff, Long.MAX_VALUE);
188         Assert.assertTrue(mDirectReportTestHelper.errorWhenBelowExpectedRate(),
189                 rateWhenMicToggleOff
190                         > SensorRatePermissionDirectReportTestHelper.CAPPED_SAMPLE_RATE_HZ);
191     }
192 }
193