diff --git a/Android.mk b/Android.mk index 8b79ceba..fa2f6f86 100644 --- a/Android.mk +++ b/Android.mk @@ -21,6 +21,7 @@ else include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \ adb \ libcutils \ + libsysutils \ liblog \ libnetutils \ libpixelflinger \ diff --git a/include/sysutils/FrameworkCommand.h b/include/sysutils/FrameworkCommand.h new file mode 100644 index 00000000..952e99a9 --- /dev/null +++ b/include/sysutils/FrameworkCommand.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __FRAMEWORK_CMD_HANDLER_H +#define __FRAMEWORK_CMD_HANDLER_H + +#include "../../../frameworks/base/include/utils/List.h" + + +class FrameworkCommand { +private: + const char *mCommand; + +public: + + FrameworkCommand(const char *cmd); + virtual ~FrameworkCommand() { } + + virtual int runCommand(char *data); + + const char *getCommand() { return mCommand; } +}; + +typedef android::List FrameworkCommandCollection; +#endif diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h new file mode 100644 index 00000000..1454a6fa --- /dev/null +++ b/include/sysutils/FrameworkListener.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _FRAMEWORKSOCKETLISTENER_H +#define _FRAMEWORKSOCKETLISTENER_H + +#include "SocketListener.h" +#include "FrameworkCommand.h" + +class FrameworkListener : public SocketListener { +private: + FrameworkCommandCollection *mCommands; + +public: + FrameworkListener(const char *socketName); + virtual ~FrameworkListener() {} + +protected: + void registerCmd(FrameworkCommand *cmd); + virtual bool onDataAvailable(int socket); + +private: + void dispatchCommand(char *cmd); +}; +#endif diff --git a/include/sysutils/FrameworkManager.h b/include/sysutils/FrameworkManager.h new file mode 100644 index 00000000..8a24d333 --- /dev/null +++ b/include/sysutils/FrameworkManager.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _FRAMEWORKMANAGER_H +#define _FRAMEWORKMANAGER_H + +#include + +class FrameworkListener; + +class FrameworkManager { + int mDoorbell; // Socket used to accept connections from framework + int mFwSock; // Socket used to communicate with framework + const char *mSocketName; + + FrameworkListener *mListener; + + pthread_mutex_t mWriteMutex; + +public: + FrameworkManager(FrameworkListener *Listener); + virtual ~FrameworkManager() {} + + int run(); + int sendMsg(char *msg); + int sendMsg(char *msg, char *data); +}; +#endif diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h new file mode 100644 index 00000000..95e83a31 --- /dev/null +++ b/include/sysutils/NetlinkEvent.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _NETLINKEVENT_H +#define _NETLINKEVENT_H + +#define NL_PARAMS_MAX 32 + +class NetlinkEvent { + int mSeq; + char *mPath; + int mAction; + char *mSubsystem; + char *mParams[NL_PARAMS_MAX]; + +public: + const static int NlActionUnknown; + const static int NlActionAdd; + const static int NlActionRemove; + const static int NlActionChange; + + NetlinkEvent(); + virtual ~NetlinkEvent(); + + bool decode(char *buffer, int size); + const char *findParam(const char *paramName); + + const char *getSubsystem() { return mSubsystem; } + int getAction() { return mAction; } +}; + +#endif diff --git a/include/sysutils/NetlinkListener.h b/include/sysutils/NetlinkListener.h new file mode 100644 index 00000000..8ac811c7 --- /dev/null +++ b/include/sysutils/NetlinkListener.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _NETLINKLISTENER_H +#define _NETLINKLISTENER_H + +#include "SocketListener.h" + +class NetlinkEvent; + +class NetlinkListener : public SocketListener { + char mBuffer[64 * 1024]; + +public: + NetlinkListener(int socket); + virtual ~NetlinkListener() {} +protected: + virtual bool onDataAvailable(int socket); +}; +#endif diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h new file mode 100644 index 00000000..f079dba1 --- /dev/null +++ b/include/sysutils/SocketListener.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _SOCKETLISTENER_H +#define _SOCKETLISTENER_H + +class SocketListener { + int mSock; + int mCsock; + int mAcceptClients; + const char *mSocketName; + +public: + SocketListener(const char *socketName, bool acceptClients); + SocketListener(int socketFd, bool acceptClients); + + virtual ~SocketListener() {} + virtual int run(); + +protected: + virtual bool onDataAvailable(int socket); +}; +#endif diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk new file mode 100644 index 00000000..0b15c126 --- /dev/null +++ b/libsysutils/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + src/FrameworkManager.cpp \ + src/SocketListener.cpp \ + src/FrameworkListener.cpp \ + src/NetlinkListener.cpp \ + src/NetlinkEvent.cpp \ + src/FrameworkCommand.cpp \ + +LOCAL_MODULE:= libsysutils + +LOCAL_C_INCLUDES := $(KERNEL_HEADERS) + +LOCAL_CFLAGS := + +LOCAL_SHARED_LIBRARIES := libcutils + +include $(BUILD_SHARED_LIBRARY) diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp new file mode 100644 index 00000000..0444de5c --- /dev/null +++ b/libsysutils/src/FrameworkCommand.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#define LOG_TAG "FrameworkCommand" + +#include + +#include + +FrameworkCommand::FrameworkCommand(const char *cmd) { + mCommand = cmd; +} + +int FrameworkCommand::runCommand(char *data) { + LOGW("Command %s has no run handler!", getCommand()); + errno = ENOSYS; + return -1; +} diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp new file mode 100644 index 00000000..bbf3f3a5 --- /dev/null +++ b/libsysutils/src/FrameworkListener.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#define LOG_TAG "FrameworkListener" + +#include + +#include +#include + +FrameworkListener::FrameworkListener(const char *socketName) : + SocketListener(socketName, true) { + mCommands = new FrameworkCommandCollection(); +} + +bool FrameworkListener::onDataAvailable(int socket) { + char buffer[101]; + int len; + + if ((len = read(socket, buffer, sizeof(buffer) -1)) < 0) { + LOGE("read() failed (%s)", strerror(errno)); + return errno; + } else if (!len) { + LOGW("Lost connection to client"); + return false; + } + + int start = 0; + int i; + + buffer[len] = '\0'; + + for (i = 0; i < len; i++) { + if (buffer[i] == '\0') { + dispatchCommand(buffer + start); + start = i + 1; + } + } + return true; +} + +void FrameworkListener::registerCmd(FrameworkCommand *cmd) { + mCommands->push_back(cmd); +} + +void FrameworkListener::dispatchCommand(char *cmd) { + FrameworkCommandCollection::iterator i; + + for (i = mCommands->begin(); i != mCommands->end(); ++i) { + FrameworkCommand *c = *i; + + if (!strncmp(cmd, c->getCommand(), strlen(c->getCommand()))) { + if (c->runCommand(cmd)) { + LOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); + } + return; + } + } + + LOGE("No cmd handlers defined for '%s'", cmd); +} + diff --git a/libsysutils/src/FrameworkManager.cpp b/libsysutils/src/FrameworkManager.cpp new file mode 100644 index 00000000..5dceb9f1 --- /dev/null +++ b/libsysutils/src/FrameworkManager.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LOG_TAG "FrameworkManager" +#include + +#include +#include + +FrameworkManager::FrameworkManager(FrameworkListener *Listener) { + mDoorbell = -1; + mFwSock = -1; + mListener = Listener; + + pthread_mutex_init(&mWriteMutex, NULL); +} + +int FrameworkManager::run() { + + if (mListener->run()) { + LOGE("Error running listener (%s)", strerror(errno)); + return -1; + } + + return 0; +} + +/* ======== + * Privates + * ======== + */ + +int FrameworkManager::sendMsg(char *msg) { + LOGD("FrameworkManager::sendMsg(%s)", msg); + if (mFwSock < 0) { + errno = EHOSTUNREACH; + return -1; + } + + pthread_mutex_lock(&mWriteMutex); + if (write(mFwSock, msg, strlen(msg) +1) < 0) { + LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno)); + } + pthread_mutex_unlock(&mWriteMutex); + return 0; +} + +int FrameworkManager::sendMsg(char *msg, char *data) { + char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1); + if (!buffer) { + errno = -ENOMEM; + return -1; + } + strcpy(buffer, msg); + strcat(buffer, data); + return sendMsg(buffer); +} diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp new file mode 100644 index 00000000..69cd3e7b --- /dev/null +++ b/libsysutils/src/NetlinkEvent.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#define LOG_TAG "NetlinkEvent" +#include + +#include + +const int NetlinkEvent::NlActionUnknown = 0; +const int NetlinkEvent::NlActionAdd = 1; +const int NetlinkEvent::NlActionRemove = 2; +const int NetlinkEvent::NlActionChange = 3; + +NetlinkEvent::NetlinkEvent() { + mAction = NlActionUnknown; +} + +NetlinkEvent::~NetlinkEvent() { + int i; + if (mPath) + free(mPath); + if (mSubsystem) + free(mSubsystem); + for (i = 0; i < NL_PARAMS_MAX; i++) { + if (!mParams[i]) + break; + free(mParams[i]); + } +} + +bool NetlinkEvent::decode(char *buffer, int size) { + char *s = buffer; + char *end; + int param_idx = 0; + int i; + int first = 1; + + end = s + size; + while (s < end) { + if (first) { + char *p; + for (p = s; *p != '@'; p++); + p++; + mPath = strdup(p); + first = 0; + } else { + if (!strncmp(s, "ACTION=", strlen("ACTION="))) { + char *a = s + strlen("ACTION="); + if (!strcmp(a, "add")) + mAction = NlActionAdd; + else if (!strcmp(a, "remove")) + mAction = NlActionRemove; + else if (!strcmp(a, "change")) + mAction = NlActionChange; + } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM="))) + mSeq = atoi(s + strlen("SEQNUM=")); + else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM="))) + mSubsystem = strdup(s + strlen("SUBSYSTEM=")); + else + mParams[param_idx++] = strdup(s); + } + s+= strlen(s) + 1; + } + return true; +} + +const char *NetlinkEvent::findParam(const char *paramName) { + int i; + + for (i = 0; i < NL_PARAMS_MAX; i++) { + if (!mParams[i]) + break; + if (!strncmp(mParams[i], paramName, strlen(paramName))) + return &mParams[i][strlen(paramName) + 1]; + } + + LOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); + return NULL; +} diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp new file mode 100644 index 00000000..d8713418 --- /dev/null +++ b/libsysutils/src/NetlinkListener.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include +#include + +#define LOG_TAG "NetlinkListener" +#include + +#include +#include + +NetlinkListener::NetlinkListener(int socket) : + SocketListener(socket, false) { +} + +bool NetlinkListener::onDataAvailable(int socket) +{ + LOGD("NetlinkListener::onDataAvailable()"); + + int count; + + if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) { + LOGE("recv failed (%s)", strerror(errno)); + return false; + } + + NetlinkEvent *evt = new NetlinkEvent(); + if (!evt->decode(mBuffer, count)) { + LOGE("Error decoding NetlinkEvent"); + goto out; + } + + LOGD("Ignoring '%s' netlink event", evt->getSubsystem()); + +out: + delete evt; + return true; +} diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp new file mode 100644 index 00000000..f92e30d7 --- /dev/null +++ b/libsysutils/src/SocketListener.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "SocketListener" +#include + +#include + +#include + +SocketListener::SocketListener(const char *socketName, bool acceptClients) { + mAcceptClients = acceptClients; + mCsock = -1; + mSocketName = socketName; + mSock = -1; +} + +SocketListener::SocketListener(int socketFd, bool acceptClients) { + mAcceptClients = acceptClients; + mCsock = -1; + mSocketName = NULL; + mSock = socketFd; +} + +int SocketListener::run() { + + if (!mSocketName && mSock == -1) { + errno = EINVAL; + return -1; + } else if (mSocketName) { + if ((mSock = android_get_control_socket(mSocketName)) < 0) { + LOGE("Obtaining file descriptor socket '%s' failed: %s", + mSocketName, strerror(errno)); + return -1; + } + } + + if (mAcceptClients) { + if (listen(mSock, 4) < 0) { + LOGE("Unable to listen on socket (%s)", strerror(errno)); + return -1; + } + } + + while(1) { + fd_set read_fds; + struct timeval to; + int max = 0; + int rc = 0; + + to.tv_sec = 60 * 60; + to.tv_usec = 0; + + FD_ZERO(&read_fds); + + if ((mAcceptClients == false) || + (mAcceptClients == true && mCsock == -1)) { + FD_SET(mSock, &read_fds); + max = mSock; + } else if (mCsock != -1) { + FD_SET(mCsock, &read_fds); + max = mCsock; + } + + if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) { + LOGE("select failed (%s)", strerror(errno)); + return -errno; + } else if (!rc) + continue; + else if (FD_ISSET(mSock, &read_fds)) { + /* + * If we're accepting client connections then + * accept and gobble the event. Otherwise + * pass it on to the handlers. + */ + if (mAcceptClients) { + struct sockaddr addr; + socklen_t alen = sizeof(addr); + + if ((mCsock = accept(mSock, &addr, &alen)) < 0) { + LOGE("accept failed (%s)", strerror(errno)); + return -errno; + } + LOGD("SocketListener client connection accepted"); + } else if (!onDataAvailable(mSock)) { + LOGW("SocketListener closing listening socket (Will shut down)"); + close(mSock); + return -ESHUTDOWN; + } + } else if ((FD_ISSET(mCsock, &read_fds)) && + !onDataAvailable(mCsock)) { + /* + * Once mCsock == -1, we'll start + * accepting connections on mSock again. + */ + LOGD("SocketListener closing client socket"); + close(mCsock); + mCsock = -1; + } + } + return 0; +} + +bool SocketListener::onDataAvailable(int socket) { + return false; +}