1 /*
2  * Copyright (C) 2016 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 #include <algorithm>
18 
19 #include "chre/core/sensor_request.h"
20 #include "chre/platform/assert.h"
21 #include "chre/platform/fatal_error.h"
22 
23 namespace chre {
24 namespace {
25 
26 Nanoseconds getBatchInterval(const SensorRequest &request) {
27   // With capping in SensorRequest constructor, interval + latency < UINT64_MAX.
28   // When the return value is default, request latency (instead of batch
29   // interval) will be used to compute the merged latency.
30   if (request.getInterval() == Nanoseconds(CHRE_SENSOR_INTERVAL_DEFAULT) ||
31       request.getLatency() == Nanoseconds(CHRE_SENSOR_LATENCY_DEFAULT)) {
32     return Nanoseconds(CHRE_SENSOR_BATCH_INTERVAL_DEFAULT);
33   } else {
34     return request.getInterval() + request.getLatency();
35   }
36 }
37 
38 }  // namespace
39 
40 SensorRequest::SensorRequest()
41     : SensorRequest(SensorMode::Off, Nanoseconds(CHRE_SENSOR_INTERVAL_DEFAULT),
42                     Nanoseconds(CHRE_SENSOR_LATENCY_DEFAULT)) {}
43 
44 SensorRequest::SensorRequest(SensorMode mode, Nanoseconds interval,
45                              Nanoseconds latency)
46     : SensorRequest(kInvalidInstanceId, mode, interval, latency) {}
47 
48 SensorRequest::SensorRequest(uint32_t instanceId, SensorMode mode,
49                              Nanoseconds interval, Nanoseconds latency)
50     : mInterval(interval),
51       mLatency(latency),
52       mInstanceId(instanceId),
53       mMode(mode) {
54   // cap non-default interval/latency to ensure no overflow in CHRE internal
55   // operations.
56   if (interval != Nanoseconds(CHRE_SENSOR_INTERVAL_DEFAULT)) {
57     mInterval = std::min(interval, Nanoseconds(kMaxIntervalLatencyNs));
58   }
59   if (latency != Nanoseconds(CHRE_SENSOR_LATENCY_DEFAULT)) {
60     mLatency = std::min(latency, Nanoseconds(kMaxIntervalLatencyNs));
61   }
62 }
63 
64 bool SensorRequest::isEquivalentTo(const SensorRequest &request) const {
65   return (mMode == request.mMode && mInterval == request.mInterval &&
66           mLatency == request.mLatency);
67 }
68 
69 bool SensorRequest::mergeWith(const SensorRequest &request) {
70   bool attributesChanged = false;
71   if (request.mMode != SensorMode::Off) {
72     // Calculate minimum batch interval before mInterval is modified.
73     Nanoseconds batchInterval =
74         std::min(getBatchInterval(*this), getBatchInterval(request));
75 
76     if (request.mInterval < mInterval) {
77       mInterval = request.mInterval;
78       attributesChanged = true;
79     }
80 
81     if (batchInterval == Nanoseconds(CHRE_SENSOR_BATCH_INTERVAL_DEFAULT)) {
82       // If batchInterval is default, it can't be effectively calculated.
83       // Use request.mLatency for more aggressive latency merging in this case.
84       Nanoseconds latency = request.mLatency;
85       if (latency < mLatency) {
86         mLatency = latency;
87         attributesChanged = true;
88       }
89     } else {
90       Nanoseconds latency = (batchInterval - mInterval);
91 
92       // Note that while batchInterval can only shrink after merging, latency
93       // can grow if the merged interval is lower.
94       // Also, it's guaranteed that latency <= kMaxIntervalLatencyNs.
95       if (latency != mLatency) {
96         mLatency = latency;
97         attributesChanged = true;
98       }
99     }
100 
101     // Compute the highest priority mode. Active continuous is the highest
102     // priority and passive one-shot is the lowest.
103     SensorMode maximalSensorMode = SensorMode::Off;
104     if (mMode == SensorMode::ActiveContinuous ||
105         request.mMode == SensorMode::ActiveContinuous) {
106       maximalSensorMode = SensorMode::ActiveContinuous;
107     } else if (mMode == SensorMode::ActiveOneShot ||
108                request.mMode == SensorMode::ActiveOneShot) {
109       maximalSensorMode = SensorMode::ActiveOneShot;
110     } else if (mMode == SensorMode::PassiveContinuous ||
111                request.mMode == SensorMode::PassiveContinuous) {
112       maximalSensorMode = SensorMode::PassiveContinuous;
113     } else if (mMode == SensorMode::PassiveOneShot ||
114                request.mMode == SensorMode::PassiveOneShot) {
115       maximalSensorMode = SensorMode::PassiveOneShot;
116     } else {
117       CHRE_ASSERT(false);
118     }
119 
120     if (mMode != maximalSensorMode) {
121       mMode = maximalSensorMode;
122       attributesChanged = true;
123     }
124   }
125 
126   return attributesChanged;
127 }
128 
129 }  // namespace chre
130