1 /*
2  * Copyright (C) 2021 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 #define LOG_TAG "GnssNavigationMessageAidl"
18 
19 #include "GnssNavigationMessageInterface.h"
20 #include <aidl/android/hardware/gnss/BnGnss.h>
21 #include <log/log.h>
22 #include "Utils.h"
23 
24 namespace aidl::android::hardware::gnss {
25 
26 using namespace ::android::hardware::gnss;
27 using GnssNavigationMessage = IGnssNavigationMessageCallback::GnssNavigationMessage;
28 using GnssNavigationMessageType = GnssNavigationMessage::GnssNavigationMessageType;
29 
30 std::shared_ptr<IGnssNavigationMessageCallback> GnssNavigationMessageInterface::sCallback = nullptr;
31 
GnssNavigationMessageInterface()32 GnssNavigationMessageInterface::GnssNavigationMessageInterface() : mMinIntervalMillis(1000) {
33     mThreads.reserve(2);
34 }
35 
~GnssNavigationMessageInterface()36 GnssNavigationMessageInterface::~GnssNavigationMessageInterface() {
37     waitForStoppingThreads();
38 }
39 
setCallback(const std::shared_ptr<IGnssNavigationMessageCallback> & callback)40 ndk::ScopedAStatus GnssNavigationMessageInterface::setCallback(
41         const std::shared_ptr<IGnssNavigationMessageCallback>& callback) {
42     ALOGD("setCallback");
43     std::unique_lock<std::mutex> lock(mMutex);
44     sCallback = callback;
45     start();
46     return ndk::ScopedAStatus::ok();
47 }
48 
close()49 ndk::ScopedAStatus GnssNavigationMessageInterface::close() {
50     ALOGD("close");
51     if (mIsActive) {
52         stop();
53     }
54     std::unique_lock<std::mutex> lock(mMutex);
55     sCallback = nullptr;
56     return ndk::ScopedAStatus::ok();
57 }
58 
start()59 void GnssNavigationMessageInterface::start() {
60     ALOGD("start");
61 
62     if (mIsActive) {
63         ALOGD("restarting since nav msg has started");
64         stop();
65     }
66 
67     mIsActive = true;
68     mThreads.emplace_back(std::thread([this]() {
69         waitForStoppingThreads();
70         mThreadBlocker.reset();
71         do {
72             if (!mIsActive) {
73                 break;
74             }
75             GnssNavigationMessage message = {
76                     .svid = 19,
77                     .type = GnssNavigationMessageType::GPS_L1CA,
78                     .status = GnssNavigationMessage::STATUS_PARITY_PASSED,
79                     .messageId = 2,
80                     .submessageId = 3,
81                     .data = std::vector<uint8_t>(40, 0xF9),
82             };
83             this->reportMessage(message);
84         } while (mIsActive &&
85                  mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMillis)));
86     }));
87 }
88 
stop()89 void GnssNavigationMessageInterface::stop() {
90     ALOGD("stop");
91     mIsActive = false;
92     mThreadBlocker.notify();
93     for (auto iter = mThreads.begin(); iter != mThreads.end();) {
94         if (iter->joinable()) {
95             // Store the thread object by value
96             std::thread threadToMove = std::move(*iter);
97 
98             mFutures.push_back(std::async(std::launch::async,
99                                           [threadToMove = std::move(threadToMove)]() mutable {
100                                               ALOGD("joining thread");
101                                               threadToMove.join();
102                                           }));
103         }
104         iter = mThreads.erase(iter);
105     }
106 }
107 
reportMessage(const GnssNavigationMessage & message)108 void GnssNavigationMessageInterface::reportMessage(const GnssNavigationMessage& message) {
109     ALOGD("reportMessage()");
110     std::shared_ptr<IGnssNavigationMessageCallback> callbackCopy;
111     {
112         std::unique_lock<std::mutex> lock(mMutex);
113         if (sCallback == nullptr) {
114             ALOGE("%s: GnssNavigationMessageInterface::sCallback is null.", __func__);
115             return;
116         }
117         callbackCopy = sCallback;
118     }
119     callbackCopy->gnssNavigationMessageCb(message);
120 }
121 
waitForStoppingThreads()122 void GnssNavigationMessageInterface::waitForStoppingThreads() {
123     for (auto& future : mFutures) {
124         ALOGD("Stopping previous thread.");
125         future.wait();
126         ALOGD("Done stopping thread.");
127     }
128     mFutures.clear();
129 }
130 
131 }  // namespace aidl::android::hardware::gnss
132