ALooperRoster.cpp revision fa8b4792228083a4c95e8bd1c28690d44bb48bd6
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
28namespace android {
29
30static bool verboseStats = false;
31
32ALooperRoster::ALooperRoster()
33    : mNextHandlerID(1),
34      mNextReplyID(1) {
35}
36
37ALooper::handler_id ALooperRoster::registerHandler(
38        const sp<ALooper> looper, const sp<AHandler> &handler) {
39    Mutex::Autolock autoLock(mLock);
40
41    if (handler->id() != 0) {
42        CHECK(!"A handler must only be registered once.");
43        return INVALID_OPERATION;
44    }
45
46    HandlerInfo info;
47    info.mLooper = looper;
48    info.mHandler = handler;
49    ALooper::handler_id handlerID = mNextHandlerID++;
50    mHandlers.add(handlerID, info);
51
52    handler->setID(handlerID, looper);
53
54    return handlerID;
55}
56
57void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
58    Mutex::Autolock autoLock(mLock);
59
60    ssize_t index = mHandlers.indexOfKey(handlerID);
61
62    if (index < 0) {
63        return;
64    }
65
66    const HandlerInfo &info = mHandlers.valueAt(index);
67
68    sp<AHandler> handler = info.mHandler.promote();
69
70    if (handler != NULL) {
71        handler->setID(0, NULL);
72    }
73
74    mHandlers.removeItemsAt(index);
75}
76
77void ALooperRoster::unregisterStaleHandlers() {
78
79    Vector<sp<ALooper> > activeLoopers;
80    {
81        Mutex::Autolock autoLock(mLock);
82
83        for (size_t i = mHandlers.size(); i-- > 0;) {
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
103status_t ALooperRoster::postAndAwaitResponse(
104        const sp<AMessage> &msg, sp<AMessage> *response) {
105    Mutex::Autolock autoLock(mLock);
106
107    uint32_t replyID = mNextReplyID++;
108
109    msg->setInt32("replyID", replyID);
110
111    status_t err = msg->post(0 /* delayUs */);
112    if (err != OK) {
113        response->clear();
114        return err;
115    }
116
117    ssize_t index;
118    while ((index = mReplies.indexOfKey(replyID)) < 0) {
119        mRepliesCondition.wait(mLock);
120    }
121
122    *response = mReplies.valueAt(index);
123    mReplies.removeItemsAt(index);
124
125    return OK;
126}
127
128void ALooperRoster::postReply(uint32_t replyID, const sp<AMessage> &reply) {
129    Mutex::Autolock autoLock(mLock);
130
131    CHECK(mReplies.indexOfKey(replyID) < 0);
132    mReplies.add(replyID, reply);
133    mRepliesCondition.broadcast();
134}
135
136static void makeFourCC(uint32_t fourcc, char *s) {
137    s[0] = (fourcc >> 24) & 0xff;
138    if (s[0]) {
139        s[1] = (fourcc >> 16) & 0xff;
140        s[2] = (fourcc >> 8) & 0xff;
141        s[3] = fourcc & 0xff;
142        s[4] = 0;
143    } else {
144        sprintf(s, "%u", fourcc);
145    }
146}
147
148void ALooperRoster::dump(int fd, const Vector<String16>& args) {
149    bool clear = false;
150    bool oldVerbose = verboseStats;
151    for (size_t i = 0; i < args.size(); i++) {
152        if (args[i] == String16("-c")) {
153            clear = true;
154        } else if (args[i] == String16("-von")) {
155            verboseStats = true;
156        } else if (args[i] == String16("-voff")) {
157            verboseStats = false;
158        }
159    }
160    String8 s;
161    if (verboseStats && !oldVerbose) {
162        s.append("(verbose stats collection enabled, stats will be cleared)\n");
163    }
164
165    Mutex::Autolock autoLock(mLock);
166    size_t n = mHandlers.size();
167    s.appendFormat(" %zu registered handlers:\n", n);
168
169    for (size_t i = 0; i < n; i++) {
170        s.appendFormat("  %d: ", mHandlers.keyAt(i));
171        HandlerInfo &info = mHandlers.editValueAt(i);
172        sp<ALooper> looper = info.mLooper.promote();
173        if (looper != NULL) {
174            s.append(looper->getName());
175            sp<AHandler> handler = info.mHandler.promote();
176            if (handler != NULL) {
177                handler->mVerboseStats = verboseStats;
178                s.appendFormat(": %u messages processed", handler->mMessageCounter);
179                if (verboseStats) {
180                    for (size_t j = 0; j < handler->mMessages.size(); j++) {
181                        char fourcc[15];
182                        makeFourCC(handler->mMessages.keyAt(j), fourcc);
183                        s.appendFormat("\n    %s: %u",
184                                fourcc,
185                                handler->mMessages.valueAt(j));
186                    }
187                } else {
188                    handler->mMessages.clear();
189                }
190                if (clear || (verboseStats && !oldVerbose)) {
191                    handler->mMessageCounter = 0;
192                    handler->mMessages.clear();
193                }
194            } else {
195                s.append(": <stale handler>");
196            }
197        } else {
198            s.append("<stale>");
199        }
200        s.append("\n");
201    }
202    write(fd, s.string(), s.size());
203}
204
205}  // namespace android
206