1 /*
2  * Copyright (C) 2017 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 "halstate.h"
18 
HalState()19 HalState::HalState() : mState(State::Constructed) {
20 }
21 
init()22 bool HalState::init() {
23     // Ensure that checking the state and waiting on the condition is atomic.
24     std::unique_lock<std::mutex> lock(mStateMutex);
25 
26     if (mState != State::Stopped && mState != State::Constructed) {
27         // We can only initialize when freshly constructed or stopped
28         return false;
29     }
30     if (mInfo) {
31         // We are in the correct state but our info object is still allocated.
32         // This is a logic error somewhere and should not happen.
33         return false;
34     }
35     auto info = std::make_unique<Info>();
36     if (info->init()) {
37         // Only store the info object to keep it alive if init succeeded.
38         // Otherwise we're going to remain in the previous state and having an
39         // uninitialized info object around will cause inconsistency.
40         mInfo = std::move(info);
41         mState = State::Initialized;
42         return true;
43     }
44     // If we failed to initalize we remain in the same state.
45     return false;
46 }
47 
stop(StopHandler stopHandler)48 bool HalState::stop(StopHandler stopHandler) {
49     {
50         // Ensure atomicity in checking and setting state
51         std::unique_lock<std::mutex> lock(mStateMutex);
52 
53         if (mState == State::Stopping || mState == State::Stopped) {
54             // Already stopping or stopped, nothing to do
55             return false;
56         }
57         if (mState != State::Running) {
58             // Make sure there is no info object anymore. It should never exist
59             // in the stopped state.
60             mInfo.reset();
61             // If we're neither stopping, stopped nor running then we can't stop
62             // again. It seems that sometimes the client expects to be able to
63             // call this when initialized or constructed so we'll set the state
64             // to stopped. We have to return false to prevent the caller from
65             // waiting for the callback though. Calling the callback here from
66             // the same thread that called stop could cause a deadlock.
67             mState = State::Stopped;
68             return false;
69         }
70         mState = State::Stopping;
71     }
72     mInfo->stop(std::bind(&HalState::onStop, this, stopHandler));
73     // We have now requested the stop, we'll change state in the stop handler
74     // when it's called.
75     return true;
76 }
77 
eventLoop()78 bool HalState::eventLoop() {
79     {
80         // Atomically check and set state to running
81         std::unique_lock<std::mutex> lock(mStateMutex);
82         if (mState != State::Initialized || !mInfo) {
83             return false;
84         }
85         mState = State::Running;
86     }
87     mInfo->eventLoop();
88     return true;
89 }
90 
info()91 Info* HalState::info() {
92     return mInfo.get();
93 }
94 
onStop(StopHandler stopHandler)95 void HalState::onStop(StopHandler stopHandler) {
96     stopHandler();
97     mInfo.reset();
98 
99     std::unique_lock<std::mutex> lock(mStateMutex);
100     mState = State::Stopped;
101 }
102 
103