xref: /aosp_15_r20/system/chre/chpp/clients/timesync.c (revision 84e339476a462649f82315436d70fd732297a399)
1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker  *
4*84e33947SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker  *
8*84e33947SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker  *
10*84e33947SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker  * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker  */
16*84e33947SAndroid Build Coastguard Worker 
17*84e33947SAndroid Build Coastguard Worker #include "chpp/clients/timesync.h"
18*84e33947SAndroid Build Coastguard Worker 
19*84e33947SAndroid Build Coastguard Worker #include <stdbool.h>
20*84e33947SAndroid Build Coastguard Worker #include <stddef.h>
21*84e33947SAndroid Build Coastguard Worker #include <stdint.h>
22*84e33947SAndroid Build Coastguard Worker #include <string.h>
23*84e33947SAndroid Build Coastguard Worker 
24*84e33947SAndroid Build Coastguard Worker #include "chpp/app.h"
25*84e33947SAndroid Build Coastguard Worker #include "chpp/clients.h"
26*84e33947SAndroid Build Coastguard Worker #include "chpp/common/timesync.h"
27*84e33947SAndroid Build Coastguard Worker #include "chpp/log.h"
28*84e33947SAndroid Build Coastguard Worker #include "chpp/memory.h"
29*84e33947SAndroid Build Coastguard Worker #include "chpp/time.h"
30*84e33947SAndroid Build Coastguard Worker #include "chpp/transport.h"
31*84e33947SAndroid Build Coastguard Worker 
32*84e33947SAndroid Build Coastguard Worker #include "chpp/clients/discovery.h"
33*84e33947SAndroid Build Coastguard Worker 
34*84e33947SAndroid Build Coastguard Worker /************************************************
35*84e33947SAndroid Build Coastguard Worker  *  Private Definitions
36*84e33947SAndroid Build Coastguard Worker  ***********************************************/
37*84e33947SAndroid Build Coastguard Worker 
38*84e33947SAndroid Build Coastguard Worker /**
39*84e33947SAndroid Build Coastguard Worker  * Structure to maintain state for the Timesync client and its Request/Response
40*84e33947SAndroid Build Coastguard Worker  * (RR) functionality.
41*84e33947SAndroid Build Coastguard Worker  */
42*84e33947SAndroid Build Coastguard Worker struct ChppTimesyncClientState {
43*84e33947SAndroid Build Coastguard Worker   struct ChppEndpointState client;                // CHPP client state
44*84e33947SAndroid Build Coastguard Worker   struct ChppOutgoingRequestState measureOffset;  // Request response state
45*84e33947SAndroid Build Coastguard Worker 
46*84e33947SAndroid Build Coastguard Worker   struct ChppTimesyncResult timesyncResult;  // Result of measureOffset
47*84e33947SAndroid Build Coastguard Worker };
48*84e33947SAndroid Build Coastguard Worker 
49*84e33947SAndroid Build Coastguard Worker /************************************************
50*84e33947SAndroid Build Coastguard Worker  *  Public Functions
51*84e33947SAndroid Build Coastguard Worker  ***********************************************/
52*84e33947SAndroid Build Coastguard Worker 
chppTimesyncClientInit(struct ChppAppState * appState)53*84e33947SAndroid Build Coastguard Worker void chppTimesyncClientInit(struct ChppAppState *appState) {
54*84e33947SAndroid Build Coastguard Worker   CHPP_LOGD("Timesync client init");
55*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState);
56*84e33947SAndroid Build Coastguard Worker 
57*84e33947SAndroid Build Coastguard Worker   appState->timesyncClientContext =
58*84e33947SAndroid Build Coastguard Worker       chppMalloc(sizeof(struct ChppTimesyncClientState));
59*84e33947SAndroid Build Coastguard Worker   CHPP_NOT_NULL(appState->timesyncClientContext);
60*84e33947SAndroid Build Coastguard Worker   struct ChppTimesyncClientState *state = appState->timesyncClientContext;
61*84e33947SAndroid Build Coastguard Worker 
62*84e33947SAndroid Build Coastguard Worker   memset(state, 0, sizeof(struct ChppTimesyncClientState));
63*84e33947SAndroid Build Coastguard Worker   state->client.appContext = appState;
64*84e33947SAndroid Build Coastguard Worker   state->timesyncResult.error = CHPP_APP_ERROR_NONE;
65*84e33947SAndroid Build Coastguard Worker 
66*84e33947SAndroid Build Coastguard Worker   chppClientInit(&state->client, CHPP_HANDLE_TIMESYNC);
67*84e33947SAndroid Build Coastguard Worker   state->timesyncResult.error = CHPP_APP_ERROR_UNSPECIFIED;
68*84e33947SAndroid Build Coastguard Worker   state->client.openState = CHPP_OPEN_STATE_OPENED;
69*84e33947SAndroid Build Coastguard Worker }
70*84e33947SAndroid Build Coastguard Worker 
chppTimesyncClientDeinit(struct ChppAppState * appState)71*84e33947SAndroid Build Coastguard Worker void chppTimesyncClientDeinit(struct ChppAppState *appState) {
72*84e33947SAndroid Build Coastguard Worker   CHPP_LOGD("Timesync client deinit");
73*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState);
74*84e33947SAndroid Build Coastguard Worker   CHPP_NOT_NULL(appState->timesyncClientContext);
75*84e33947SAndroid Build Coastguard Worker   chppClientDeinit(&appState->timesyncClientContext->client);
76*84e33947SAndroid Build Coastguard Worker   CHPP_FREE_AND_NULLIFY(appState->timesyncClientContext);
77*84e33947SAndroid Build Coastguard Worker }
78*84e33947SAndroid Build Coastguard Worker 
chppTimesyncClientReset(struct ChppAppState * appState)79*84e33947SAndroid Build Coastguard Worker void chppTimesyncClientReset(struct ChppAppState *appState) {
80*84e33947SAndroid Build Coastguard Worker   CHPP_LOGD("Timesync client reset");
81*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState);
82*84e33947SAndroid Build Coastguard Worker   struct ChppTimesyncClientState *state = appState->timesyncClientContext;
83*84e33947SAndroid Build Coastguard Worker   CHPP_NOT_NULL(state);
84*84e33947SAndroid Build Coastguard Worker 
85*84e33947SAndroid Build Coastguard Worker   state->timesyncResult.error = CHPP_APP_ERROR_NONE;
86*84e33947SAndroid Build Coastguard Worker   state->timesyncResult.offsetNs = 0;
87*84e33947SAndroid Build Coastguard Worker   state->timesyncResult.rttNs = 0;
88*84e33947SAndroid Build Coastguard Worker   state->timesyncResult.measurementTimeNs = 0;
89*84e33947SAndroid Build Coastguard Worker }
90*84e33947SAndroid Build Coastguard Worker 
chppDispatchTimesyncServiceResponse(struct ChppAppState * appState,const uint8_t * buf,size_t len)91*84e33947SAndroid Build Coastguard Worker bool chppDispatchTimesyncServiceResponse(struct ChppAppState *appState,
92*84e33947SAndroid Build Coastguard Worker                                          const uint8_t *buf, size_t len) {
93*84e33947SAndroid Build Coastguard Worker   CHPP_LOGD("Timesync client dispatch service response");
94*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState);
95*84e33947SAndroid Build Coastguard Worker   struct ChppTimesyncClientState *state = appState->timesyncClientContext;
96*84e33947SAndroid Build Coastguard Worker   CHPP_NOT_NULL(state);
97*84e33947SAndroid Build Coastguard Worker   CHPP_NOT_NULL(buf);
98*84e33947SAndroid Build Coastguard Worker 
99*84e33947SAndroid Build Coastguard Worker   if (len < sizeof(struct ChppTimesyncResponse)) {
100*84e33947SAndroid Build Coastguard Worker     CHPP_LOGE("Timesync resp short len=%" PRIuSIZE, len);
101*84e33947SAndroid Build Coastguard Worker     state->timesyncResult.error = CHPP_APP_ERROR_INVALID_LENGTH;
102*84e33947SAndroid Build Coastguard Worker     return false;
103*84e33947SAndroid Build Coastguard Worker   }
104*84e33947SAndroid Build Coastguard Worker 
105*84e33947SAndroid Build Coastguard Worker   const struct ChppTimesyncResponse *response =
106*84e33947SAndroid Build Coastguard Worker       (const struct ChppTimesyncResponse *)buf;
107*84e33947SAndroid Build Coastguard Worker   if (chppTimestampIncomingResponse(state->client.appContext,
108*84e33947SAndroid Build Coastguard Worker                                     &state->measureOffset, &response->header)) {
109*84e33947SAndroid Build Coastguard Worker     state->timesyncResult.rttNs = state->measureOffset.responseTimeNs -
110*84e33947SAndroid Build Coastguard Worker                                   state->measureOffset.requestTimeNs;
111*84e33947SAndroid Build Coastguard Worker     int64_t offsetNs =
112*84e33947SAndroid Build Coastguard Worker         (int64_t)(response->timeNs - state->measureOffset.responseTimeNs);
113*84e33947SAndroid Build Coastguard Worker     int64_t offsetChangeNs = offsetNs - state->timesyncResult.offsetNs;
114*84e33947SAndroid Build Coastguard Worker 
115*84e33947SAndroid Build Coastguard Worker     int64_t clippedOffsetChangeNs = offsetChangeNs;
116*84e33947SAndroid Build Coastguard Worker     if (state->timesyncResult.offsetNs != 0) {
117*84e33947SAndroid Build Coastguard Worker       clippedOffsetChangeNs = MIN(clippedOffsetChangeNs,
118*84e33947SAndroid Build Coastguard Worker                                   (int64_t)CHPP_CLIENT_TIMESYNC_MAX_CHANGE_NS);
119*84e33947SAndroid Build Coastguard Worker       clippedOffsetChangeNs = MAX(clippedOffsetChangeNs,
120*84e33947SAndroid Build Coastguard Worker                                   -(int64_t)CHPP_CLIENT_TIMESYNC_MAX_CHANGE_NS);
121*84e33947SAndroid Build Coastguard Worker     }
122*84e33947SAndroid Build Coastguard Worker 
123*84e33947SAndroid Build Coastguard Worker     state->timesyncResult.offsetNs += clippedOffsetChangeNs;
124*84e33947SAndroid Build Coastguard Worker 
125*84e33947SAndroid Build Coastguard Worker     if (offsetChangeNs != clippedOffsetChangeNs) {
126*84e33947SAndroid Build Coastguard Worker       CHPP_LOGW("Drift=%" PRId64 " clipped to %" PRId64 " at t=%" PRIu64,
127*84e33947SAndroid Build Coastguard Worker                 offsetChangeNs / (int64_t)CHPP_NSEC_PER_MSEC,
128*84e33947SAndroid Build Coastguard Worker                 clippedOffsetChangeNs / (int64_t)CHPP_NSEC_PER_MSEC,
129*84e33947SAndroid Build Coastguard Worker                 state->measureOffset.responseTimeNs / CHPP_NSEC_PER_MSEC);
130*84e33947SAndroid Build Coastguard Worker     } else {
131*84e33947SAndroid Build Coastguard Worker       state->timesyncResult.measurementTimeNs =
132*84e33947SAndroid Build Coastguard Worker           state->measureOffset.responseTimeNs;
133*84e33947SAndroid Build Coastguard Worker     }
134*84e33947SAndroid Build Coastguard Worker 
135*84e33947SAndroid Build Coastguard Worker     state->timesyncResult.error = CHPP_APP_ERROR_NONE;
136*84e33947SAndroid Build Coastguard Worker 
137*84e33947SAndroid Build Coastguard Worker     CHPP_LOGD("Timesync RTT=%" PRIu64 " correction=%" PRId64 " offset=%" PRId64
138*84e33947SAndroid Build Coastguard Worker               " t=%" PRIu64,
139*84e33947SAndroid Build Coastguard Worker               state->timesyncResult.rttNs / CHPP_NSEC_PER_MSEC,
140*84e33947SAndroid Build Coastguard Worker               clippedOffsetChangeNs / (int64_t)CHPP_NSEC_PER_MSEC,
141*84e33947SAndroid Build Coastguard Worker               offsetNs / (int64_t)CHPP_NSEC_PER_MSEC,
142*84e33947SAndroid Build Coastguard Worker               state->timesyncResult.measurementTimeNs / CHPP_NSEC_PER_MSEC);
143*84e33947SAndroid Build Coastguard Worker   }
144*84e33947SAndroid Build Coastguard Worker 
145*84e33947SAndroid Build Coastguard Worker   return true;
146*84e33947SAndroid Build Coastguard Worker }
147*84e33947SAndroid Build Coastguard Worker 
chppTimesyncMeasureOffset(struct ChppAppState * appState)148*84e33947SAndroid Build Coastguard Worker bool chppTimesyncMeasureOffset(struct ChppAppState *appState) {
149*84e33947SAndroid Build Coastguard Worker   bool result = false;
150*84e33947SAndroid Build Coastguard Worker   CHPP_LOGD("Measuring timesync t=%" PRIu64,
151*84e33947SAndroid Build Coastguard Worker             chppGetCurrentTimeNs() / CHPP_NSEC_PER_MSEC);
152*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState);
153*84e33947SAndroid Build Coastguard Worker   struct ChppTimesyncClientState *state = appState->timesyncClientContext;
154*84e33947SAndroid Build Coastguard Worker   CHPP_NOT_NULL(state);
155*84e33947SAndroid Build Coastguard Worker 
156*84e33947SAndroid Build Coastguard Worker   state->timesyncResult.error =
157*84e33947SAndroid Build Coastguard Worker       CHPP_APP_ERROR_BUSY;  // A measurement is in progress
158*84e33947SAndroid Build Coastguard Worker 
159*84e33947SAndroid Build Coastguard Worker   struct ChppAppHeader *request = chppAllocClientRequestCommand(
160*84e33947SAndroid Build Coastguard Worker       &state->client, CHPP_TIMESYNC_COMMAND_GETTIME);
161*84e33947SAndroid Build Coastguard Worker   size_t requestLen = sizeof(*request);
162*84e33947SAndroid Build Coastguard Worker 
163*84e33947SAndroid Build Coastguard Worker   if (request == NULL) {
164*84e33947SAndroid Build Coastguard Worker     state->timesyncResult.error = CHPP_APP_ERROR_OOM;
165*84e33947SAndroid Build Coastguard Worker     CHPP_LOG_OOM();
166*84e33947SAndroid Build Coastguard Worker 
167*84e33947SAndroid Build Coastguard Worker   } else if (!chppClientSendTimestampedRequestOrFail(
168*84e33947SAndroid Build Coastguard Worker                  &state->client, &state->measureOffset, request, requestLen,
169*84e33947SAndroid Build Coastguard Worker                  CHPP_REQUEST_TIMEOUT_INFINITE)) {
170*84e33947SAndroid Build Coastguard Worker     state->timesyncResult.error = CHPP_APP_ERROR_UNSPECIFIED;
171*84e33947SAndroid Build Coastguard Worker 
172*84e33947SAndroid Build Coastguard Worker   } else {
173*84e33947SAndroid Build Coastguard Worker     result = true;
174*84e33947SAndroid Build Coastguard Worker   }
175*84e33947SAndroid Build Coastguard Worker 
176*84e33947SAndroid Build Coastguard Worker   return result;
177*84e33947SAndroid Build Coastguard Worker }
178*84e33947SAndroid Build Coastguard Worker 
chppTimesyncGetOffset(struct ChppAppState * appState,uint64_t maxTimesyncAgeNs)179*84e33947SAndroid Build Coastguard Worker int64_t chppTimesyncGetOffset(struct ChppAppState *appState,
180*84e33947SAndroid Build Coastguard Worker                               uint64_t maxTimesyncAgeNs) {
181*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState);
182*84e33947SAndroid Build Coastguard Worker   struct ChppTimesyncClientState *state = appState->timesyncClientContext;
183*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(state);
184*84e33947SAndroid Build Coastguard Worker 
185*84e33947SAndroid Build Coastguard Worker   bool timesyncNeverDone = state->timesyncResult.offsetNs == 0;
186*84e33947SAndroid Build Coastguard Worker   bool timesyncIsStale =
187*84e33947SAndroid Build Coastguard Worker       chppGetCurrentTimeNs() - state->timesyncResult.measurementTimeNs >
188*84e33947SAndroid Build Coastguard Worker       maxTimesyncAgeNs;
189*84e33947SAndroid Build Coastguard Worker 
190*84e33947SAndroid Build Coastguard Worker   if (timesyncNeverDone || timesyncIsStale) {
191*84e33947SAndroid Build Coastguard Worker     chppTimesyncMeasureOffset(appState);
192*84e33947SAndroid Build Coastguard Worker   } else {
193*84e33947SAndroid Build Coastguard Worker     CHPP_LOGD("No need to timesync at t~=%" PRIu64 "offset=%" PRId64,
194*84e33947SAndroid Build Coastguard Worker               chppGetCurrentTimeNs() / CHPP_NSEC_PER_MSEC,
195*84e33947SAndroid Build Coastguard Worker               state->timesyncResult.offsetNs / (int64_t)CHPP_NSEC_PER_MSEC);
196*84e33947SAndroid Build Coastguard Worker   }
197*84e33947SAndroid Build Coastguard Worker 
198*84e33947SAndroid Build Coastguard Worker   return state->timesyncResult.offsetNs;
199*84e33947SAndroid Build Coastguard Worker }
200*84e33947SAndroid Build Coastguard Worker 
chppTimesyncGetResult(struct ChppAppState * appState)201*84e33947SAndroid Build Coastguard Worker const struct ChppTimesyncResult *chppTimesyncGetResult(
202*84e33947SAndroid Build Coastguard Worker     struct ChppAppState *appState) {
203*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState);
204*84e33947SAndroid Build Coastguard Worker   CHPP_DEBUG_NOT_NULL(appState->timesyncClientContext);
205*84e33947SAndroid Build Coastguard Worker   return &appState->timesyncClientContext->timesyncResult;
206*84e33947SAndroid Build Coastguard Worker }
207