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 package com.google.android.chre.test.chqts;
17 
18 import android.hardware.location.ContextHubInfo;
19 import android.hardware.location.ContextHubManager;
20 import android.hardware.location.NanoAppBinary;
21 
22 import java.nio.ByteBuffer;
23 import java.nio.ByteOrder;
24 import java.util.Timer;
25 import java.util.TimerTask;
26 
27 /**
28  * Checks that chreGetTime() is reasonable.
29  *
30  * We check that it's monotonically increasing, and mostly in line with
31  * the application processor's notion of time passing.
32  *
33  * Protocol:
34  * Host:    GET_TIME, no data
35  * Nanoapp: CONTINUE, 64-bit timestamp (little endian)
36  * [2.5 second pause]
37  * Host:    CONTINUE, no data
38  * Nanoapp: CONTINUE, 64-bit timestamp (little endian)
39  * [Host declares pass]
40  */
41 public class ContextHubGetTimeTestExecutor extends ContextHubGeneralTestExecutor {
42     private static final ContextHubTestConstants.TestNames TEST_NAME =
43             ContextHubTestConstants.TestNames.GET_TIME;
44 
45     // Since the CHRE timestamps are in nanoseconds, we do most of our times
46     // in nanoseconds here (although the Timer.schedule() only works with
47     // milliseconds; we elect for the shorter naming for our more common unit).
48 
49     // 2.5 seconds
50     private static final long SLEEP_DURATION_MILLISECONDS = 2500;
51     private static final long SLEEP_DURATION_NS =
52             SLEEP_DURATION_MILLISECONDS * 1000 * 1000;
53 
54     // We expect some degree of inconsistency between our host/CHRE
55     // transaction overheads, so we allow a healthy amount of tolerance
56     // here.  This isn't a precision check, but should hopefully make
57     // sure the CHRE is within the right ballpark.
58     // 0.5 seconds
59     private static final long TOLERANCE_NS = 500 * 1000 * 1000;
60 
61     private int mContinueCount = 0;
62     private long mFirstTimestamp;
63 
64     private Timer mTimer = new Timer();
65 
ContextHubGetTimeTestExecutor(ContextHubManager manager, ContextHubInfo info, NanoAppBinary binary)66     public ContextHubGetTimeTestExecutor(ContextHubManager manager, ContextHubInfo info,
67             NanoAppBinary binary) {
68         super(manager, info,
69                 new GeneralTestNanoApp(binary, ContextHubTestConstants.TestNames.GET_TIME));
70     }
71 
72     @Override
handleMessageFromNanoApp(long nanoAppId, ContextHubTestConstants.MessageType type, byte[] data)73     protected void handleMessageFromNanoApp(long nanoAppId,
74             ContextHubTestConstants.MessageType type, byte[] data) {
75         if (type != ContextHubTestConstants.MessageType.CONTINUE) {
76             fail("Unexpected message type " + type);
77             return;
78         }
79 
80         assertEquals("Expected exactly 8 bytes with CONTINUE message.",
81                 8, data.length);
82         long timestamp = ByteBuffer.wrap(data)
83                 .order(ByteOrder.LITTLE_ENDIAN)
84                 .getLong();
85 
86         mContinueCount++;
87         if (mContinueCount == 1) {
88             mFirstTimestamp = timestamp;
89             // We perform our delay before the next message in a separate
90             // thread, so we're not stalling the ContextHubManager/Service
91             // from servicing any other messages or events.
92             mTimer.schedule(new TimerTask() {
93                 @Override
94                 public void run() {
95                     byte[] emptyData = new byte[0];
96                     sendMessageToNanoAppOrFail(nanoAppId,
97                             ContextHubTestConstants.MessageType.CONTINUE.asInt(),
98                             emptyData);
99                 }
100             }, SLEEP_DURATION_MILLISECONDS);
101             // We got our first timestamp and started the (delayed) send
102             // message.  Nothing more to do this time.
103             return;
104         }
105         // This is our second call.
106         long timeDifference = timestamp - mFirstTimestamp;
107         assertTrue("Subsequent timestamps did not monotonically increase",
108                 timeDifference > 0);
109         assertTrue("Expected timestamp difference around " + SLEEP_DURATION_NS
110                         + " nanoseconds, but got " + timeDifference,
111                 ((timeDifference > (SLEEP_DURATION_NS - TOLERANCE_NS))
112                         && (timeDifference
113                         < (SLEEP_DURATION_NS + TOLERANCE_NS))));
114 
115         // The CHRE gave us two reasonable timestamps.  And the nanoapp didn't
116         // signal any issues with its testing.  We're good.
117         pass();
118     }
119 
120     @Override
deinit()121     public void deinit() {
122         // If our test aborted for another reason, we want to make sure
123         // we cancel any timer that we might have set, so we don't send
124         // a spurious message to the CHRE after this test has completed.
125         mTimer.cancel();
126 
127         super.deinit();
128     }
129 }
130