SocketListener.cpp revision d768066ef54270a0d3ccfccd50ae8238db5a2cdd
124ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes/*
224ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * Copyright (C) 2008 The Android Open Source Project
324ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes *
424ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
524ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * you may not use this file except in compliance with the License.
624ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * You may obtain a copy of the License at
724ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes *
824ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
924ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes *
1024ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * Unless required by applicable law or agreed to in writing, software
1124ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1224ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * See the License for the specific language governing permissions and
1424ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * limitations under the License.
1524ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes */
1624ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes#include <stdio.h>
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <errno.h>
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdlib.h>
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/socket.h>
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/select.h>
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/time.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/un.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "SocketListener"
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/log.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/sockets.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sysutils/SocketListener.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sysutils/SocketClient.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectSocketListener::SocketListener(const char *socketName, bool listen) {
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mListen = listen;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSocketName = socketName;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSock = -1;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_mutex_init(&mClientsLock, NULL);
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mClients = new SocketClientCollection();
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectSocketListener::SocketListener(int socketFd, bool listen) {
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mListen = listen;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSocketName = NULL;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSock = socketFd;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_mutex_init(&mClientsLock, NULL);
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mClients = new SocketClientCollection();
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint SocketListener::startListener() {
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!mSocketName && mSock == -1) {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        errno = EINVAL;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (mSocketName) {
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("Obtaining file descriptor socket '%s' failed: %s",
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 mSocketName, strerror(errno));
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mListen && listen(mSock, 4) < 0) {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Unable to listen on socket (%s)", strerror(errno));
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (!mListen) {
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mClients->push_back(new SocketClient(mSock));
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGD("Created phantom client");
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pipe(mCtrlPipe))
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this))
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint SocketListener::stopListener() {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char c = 0;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (write(mCtrlPipe[1], &c, 1) != 1) {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Error writing to control pipe (%s)", strerror(errno));
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGD("Signaled listener thread - waiting for it to die");
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void *ret;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pthread_join(mThread, &ret)) {
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Error joining to listener thread (%s)", strerror(errno));
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGD("Listener stopped");
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid *SocketListener::threadStart(void *obj) {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    me->runListener();
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGD("Listener thread shutting down");
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_exit(NULL);
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid SocketListener::runListener() {
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while(1) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SocketClientCollection::iterator it;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fd_set read_fds;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        struct timeval to;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rc = 0;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        to.tv_sec = 60 * 60;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        to.tv_usec = 0;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int max = 0;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FD_ZERO(&read_fds);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mListen) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            max = mSock;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            FD_SET(mSock, &read_fds);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FD_SET(mCtrlPipe[0], &read_fds);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCtrlPipe[0] > max)
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            max = mCtrlPipe[0];
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pthread_mutex_lock(&mClientsLock);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (it = mClients->begin(); it != mClients->end(); ++it) {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            FD_SET((*it)->getSocket(), &read_fds);
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((*it)->getSocket() > max)
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                max = (*it)->getSocket();
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pthread_mutex_unlock(&mClientsLock);
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("select failed (%s)", strerror(errno));
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sleep(1);
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (!rc) {
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGD("select timeout");
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGD("Control message received");
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mListen && FD_ISSET(mSock, &read_fds)) {
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            struct sockaddr addr;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            socklen_t alen = sizeof(addr);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int c;
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((c = accept(mSock, &addr, &alen)) < 0) {
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LOGE("accept failed (%s)", strerror(errno));
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sleep(1);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGD("SocketListener client connection accepted");
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pthread_mutex_lock(&mClientsLock);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClients->push_back(new SocketClient(c));
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pthread_mutex_unlock(&mClientsLock);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        do {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pthread_mutex_lock(&mClientsLock);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (it = mClients->begin(); it != mClients->end(); ++it) {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int fd = (*it)->getSocket();
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (FD_ISSET(fd, &read_fds)) {
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pthread_mutex_unlock(&mClientsLock);
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!onDataAvailable(*it)) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        LOGD("SocketListener closing client socket");
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        close(fd);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pthread_mutex_lock(&mClientsLock);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        delete *it;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        it = mClients->erase(it);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pthread_mutex_unlock(&mClientsLock);
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    FD_CLR(fd, &read_fds);
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pthread_mutex_unlock(&mClientsLock);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } while (0);
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid SocketListener::sendBroadcast(int code, char *msg, bool addErrno) {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_mutex_lock(&mClientsLock);
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SocketClientCollection::iterator i;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i = mClients->begin(); i != mClients->end(); ++i) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((*i)->sendMsg(code, msg, addErrno)) {
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGW("Error sending broadcast (%s)", strerror(errno));
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_mutex_unlock(&mClientsLock);
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid SocketListener::sendBroadcast(char *msg) {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_mutex_lock(&mClientsLock);
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SocketClientCollection::iterator i;
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i = mClients->begin(); i != mClients->end(); ++i) {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((*i)->sendMsg(msg)) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGW("Error sending broadcast (%s)", strerror(errno));
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_mutex_unlock(&mClientsLock);
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project