1 /*
2  * Copyright (C) 2010 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_NDEBUG 0
18 #define LOG_TAG "ALooperRoster"
19 #include <utils/Log.h>
20 #include <utils/String8.h>
21 
22 #include "ALooperRoster.h"
23 
24 #include "ADebug.h"
25 #include "AHandler.h"
26 #include "AMessage.h"
27 
28 namespace android {
29 
30 static bool verboseStats = false;
31 
ALooperRoster()32 ALooperRoster::ALooperRoster()
33     : mNextHandlerID(1) {
34 }
35 
registerHandler(const sp<ALooper> looper,const sp<AHandler> & handler)36 ALooper::handler_id ALooperRoster::registerHandler(
37         const sp<ALooper> looper, const sp<AHandler> &handler) {
38     Mutex::Autolock autoLock(mLock);
39 
40     if (handler->id() != 0) {
41         CHECK(!"A handler must only be registered once.");
42         return INVALID_OPERATION;
43     }
44 
45     HandlerInfo info;
46     info.mLooper = looper;
47     info.mHandler = handler;
48     ALooper::handler_id handlerID = mNextHandlerID++;
49     mHandlers.add(handlerID, info);
50 
51     handler->setID(handlerID, looper);
52 
53     return handlerID;
54 }
55 
unregisterHandler(ALooper::handler_id handlerID)56 void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
57     Mutex::Autolock autoLock(mLock);
58 
59     ssize_t index = mHandlers.indexOfKey(handlerID);
60 
61     if (index < 0) {
62         return;
63     }
64 
65     const HandlerInfo &info = mHandlers.valueAt(index);
66 
67     sp<AHandler> handler = info.mHandler.promote();
68 
69     if (handler != NULL) {
70         handler->setID(0, NULL);
71     }
72 
73     mHandlers.removeItemsAt(index);
74 }
75 
unregisterStaleHandlers()76 void ALooperRoster::unregisterStaleHandlers() {
77 
78     Vector<sp<ALooper> > activeLoopers;
79     {
80         Mutex::Autolock autoLock(mLock);
81 
82         for (size_t i = mHandlers.size(); i > 0;) {
83             i--;
84             const HandlerInfo &info = mHandlers.valueAt(i);
85 
86             sp<ALooper> looper = info.mLooper.promote();
87             if (looper == NULL) {
88                 ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i));
89                 mHandlers.removeItemsAt(i);
90             } else {
91                 // At this point 'looper' might be the only sp<> keeping
92                 // the object alive. To prevent it from going out of scope
93                 // and having ~ALooper call this method again recursively
94                 // and then deadlocking because of the Autolock above, add
95                 // it to a Vector which will go out of scope after the lock
96                 // has been released.
97                 activeLoopers.add(looper);
98             }
99         }
100     }
101 }
102 
makeFourCC(uint32_t fourcc,char * s)103 static void makeFourCC(uint32_t fourcc, char *s) {
104     s[0] = (fourcc >> 24) & 0xff;
105     if (s[0]) {
106         s[1] = (fourcc >> 16) & 0xff;
107         s[2] = (fourcc >> 8) & 0xff;
108         s[3] = fourcc & 0xff;
109         s[4] = 0;
110     } else {
111         sprintf(s, "%u", fourcc);
112     }
113 }
114 
dump(int fd,const Vector<String16> & args)115 void ALooperRoster::dump(int fd, const Vector<String16>& args) {
116     bool clear = false;
117     bool oldVerbose = verboseStats;
118     for (size_t i = 0; i < args.size(); i++) {
119         if (args[i] == String16("-c")) {
120             clear = true;
121         } else if (args[i] == String16("-von")) {
122             verboseStats = true;
123         } else if (args[i] == String16("-voff")) {
124             verboseStats = false;
125         }
126     }
127     String8 s;
128     if (verboseStats && !oldVerbose) {
129         s.append("(verbose stats collection enabled, stats will be cleared)\n");
130     }
131 
132     Mutex::Autolock autoLock(mLock);
133     size_t n = mHandlers.size();
134     s.appendFormat(" %zu registered handlers:\n", n);
135 
136     for (size_t i = 0; i < n; i++) {
137         s.appendFormat("  %d: ", mHandlers.keyAt(i));
138         HandlerInfo &info = mHandlers.editValueAt(i);
139         sp<ALooper> looper = info.mLooper.promote();
140         if (looper != NULL) {
141             s.append(looper->getName());
142             sp<AHandler> handler = info.mHandler.promote();
143             if (handler != NULL) {
144                 handler->mVerboseStats = verboseStats;
145                 s.appendFormat(": %u messages processed", handler->mMessageCounter);
146                 if (verboseStats) {
147                     for (size_t j = 0; j < handler->mMessages.size(); j++) {
148                         char fourcc[15];
149                         makeFourCC(handler->mMessages.keyAt(j), fourcc);
150                         s.appendFormat("\n    %s: %u",
151                                 fourcc,
152                                 handler->mMessages.valueAt(j));
153                     }
154                 } else {
155                     handler->mMessages.clear();
156                 }
157                 if (clear || (verboseStats && !oldVerbose)) {
158                     handler->mMessageCounter = 0;
159                     handler->mMessages.clear();
160                 }
161             } else {
162                 s.append(": <stale handler>");
163             }
164         } else {
165             s.append("<stale>");
166         }
167         s.append("\n");
168     }
169     write(fd, s.string(), s.size());
170 }
171 
172 }  // namespace android
173