1 /*
2  * Copyright (C) 2011 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 <stdint.h>
18 
19 #include <common_time/cc_helper.h>
20 #include <common_time/ICommonClock.h>
21 #include <utils/threads.h>
22 
23 namespace android {
24 
25 Mutex CCHelper::lock_;
26 sp<ICommonClock> CCHelper::common_clock_;
27 sp<ICommonClockListener> CCHelper::common_clock_listener_;
28 uint32_t CCHelper::ref_count_ = 0;
29 
verifyClock_l()30 bool CCHelper::verifyClock_l() {
31     bool ret = false;
32 
33     if (common_clock_ == NULL) {
34         common_clock_ = ICommonClock::getInstance();
35         if (common_clock_ == NULL)
36             goto bailout;
37     }
38 
39     if (ref_count_ > 0) {
40         if (common_clock_listener_ == NULL) {
41             common_clock_listener_ = new CommonClockListener();
42             if (common_clock_listener_ == NULL)
43                 goto bailout;
44 
45             if (OK != common_clock_->registerListener(common_clock_listener_))
46                 goto bailout;
47         }
48     }
49 
50     ret = true;
51 
52 bailout:
53     if (!ret) {
54         common_clock_listener_ = NULL;
55         common_clock_ = NULL;
56     }
57     return ret;
58 }
59 
CCHelper()60 CCHelper::CCHelper() {
61     Mutex::Autolock lock(&lock_);
62     ref_count_++;
63     verifyClock_l();
64 }
65 
~CCHelper()66 CCHelper::~CCHelper() {
67     Mutex::Autolock lock(&lock_);
68 
69     assert(ref_count_ > 0);
70     ref_count_--;
71 
72     // If we were the last CCHelper instance in the system, and we had
73     // previously register a listener, unregister it now so that the common time
74     // service has the chance to go into auto-disabled mode.
75     if (!ref_count_ &&
76        (common_clock_ != NULL) &&
77        (common_clock_listener_ != NULL)) {
78         common_clock_->unregisterListener(common_clock_listener_);
79         common_clock_listener_ = NULL;
80     }
81 }
82 
onTimelineChanged(uint64_t)83 void CCHelper::CommonClockListener::onTimelineChanged(uint64_t /*timelineID*/) {
84     // do nothing; listener is only really used as a token so the server can
85     // find out when clients die.
86 }
87 
88 // Helper methods which attempts to make calls to the common time binder
89 // service.  If the first attempt fails with DEAD_OBJECT, the helpers will
90 // attempt to make a connection to the service again (assuming that the process
91 // hosting the service had crashed and the client proxy we are holding is dead)
92 // If the second attempt fails, or no connection can be made, the we let the
93 // error propagate up the stack and let the caller deal with the situation as
94 // best they can.
95 #define CCHELPER_METHOD(decl, call)                 \
96     status_t CCHelper::decl {                       \
97         Mutex::Autolock lock(&lock_);               \
98                                                     \
99         if (!verifyClock_l())                       \
100             return DEAD_OBJECT;                     \
101                                                     \
102         status_t status = common_clock_->call;      \
103         if (DEAD_OBJECT == status) {                \
104             if (!verifyClock_l())                   \
105                 return DEAD_OBJECT;                 \
106             status = common_clock_->call;           \
107         }                                           \
108                                                     \
109         return status;                              \
110     }
111 
112 #define VERIFY_CLOCK()
113 
114 CCHELPER_METHOD(isCommonTimeValid(bool* valid, uint32_t* timelineID),
115                 isCommonTimeValid(valid, timelineID))
116 CCHELPER_METHOD(commonTimeToLocalTime(int64_t commonTime, int64_t* localTime),
117                 commonTimeToLocalTime(commonTime, localTime))
118 CCHELPER_METHOD(localTimeToCommonTime(int64_t localTime, int64_t* commonTime),
119                 localTimeToCommonTime(localTime, commonTime))
120 CCHELPER_METHOD(getCommonTime(int64_t* commonTime),
121                 getCommonTime(commonTime))
122 CCHELPER_METHOD(getCommonFreq(uint64_t* freq),
123                 getCommonFreq(freq))
124 CCHELPER_METHOD(getLocalTime(int64_t* localTime),
125                 getLocalTime(localTime))
126 CCHELPER_METHOD(getLocalFreq(uint64_t* freq),
127                 getLocalFreq(freq))
128 
129 }  // namespace android
130