Android Process & Thread
Native Service and Android Service
- Native Service:In every main() method of NativeService, which is called by init process through parseing init.rc, the globale object of ProcessState will be created by calling ProcessState::self(),and then startThreadPool and created main thread by calling IPCThreadPool.self()->joinThreadPool().
- Android Service:All Android Service is created by SystemServer and running in the same process which is system server.
New Process with main()
- int main(int argc, char** argv)
- {
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- LOGI("ServiceManager: %p", sm.get());
- AudioFlinger::instantiate();
- MediaPlayerService::instantiate();
- CameraService::instantiate();
- AudioPolicyService::instantiate();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- }
Static: private/binder/Static.h
- Static.h
- #include <utils/threads.h>
- #include <binder/IBinder.h>
- #include <binder/IMemory.h>
- #include <binder/ProcessState.h>
- #include <binder/IPermissionController.h>
- #include <binder/IServiceManager.h>
- namespace android {
- // For ProcessState.cpp
- extern Mutex gProcessMutex;
- extern sp<ProcessState> gProcess;
- // For ServiceManager.cpp
- extern Mutex gDefaultServiceManagerLock;
- extern sp<IServiceManager> gDefaultServiceManager;
- extern sp<IPermissionController> gPermissionController;
- }
- #include <utils/threads.h>
- Static.cpp
- #include <private/binder/Static.h>
- #include <binder/IPCThreadState.h>
- #include <utils/Log.h>
- namespace android {
- // ------------ ProcessState.cpp
- Mutex gProcessMutex;
- sp<ProcessState> gProcess;
- class LibUtilsIPCtStatics
- {
- public:
- LibUtilsIPCtStatics()
- {
- }
- ~LibUtilsIPCtStatics()
- {
- IPCThreadState::shutdown();
- }
- };
- static LibUtilsIPCtStatics gIPCStatics;
- // ------------ ServiceManager.cpp
- Mutex gDefaultServiceManagerLock;
- sp<IServiceManager> gDefaultServiceManager;
- sp<IPermissionController> gPermissionController;
- }
- #include <private/binder/Static.h>
- When we create new process and call main()..........,the gloable vairables will be created
- Mutex gProcessMutex;
- sp<ProcessState> gProcess;
- Mutex gDefaultServiceManagerLock;
- sp<IServiceManager> gDefaultServiceManager;
- sp<IPermissionController> gPermissionController;
- Mutex gProcessMutex;
Threads
- android.threads wrap something related to thread using linux's pthread.h
- /**
- * Copyright (C) 2007 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 _LIBS_UTILS_THREADS_H
- #define _LIBS_UTILS_THREADS_H
- #include <stdint.h>
- #include <sys/types.h>
- #include <time.h>
- #include <system/graphics.h>
- #if defined(HAVE_PTHREADS)
- # include <pthread.h>
- #endif
- // ------------------------------------------------------------------
- // C API
- #ifdef __cplusplus
- extern "C" {
- #endif
- typedef void* android_thread_id_t;
- typedef int (*android_thread_func_t)(void*);
- enum {
- /**
- * ***********************************************
- * ** Keep in sync with android.os.Process.java **
- * ***********************************************
- *
- * This maps directly to the "nice" priorities we use in Android.
- * A thread priority should be chosen inverse-proportionally to
- * the amount of work the thread is expected to do. The more work
- * a thread will do, the less favorable priority it should get so that
- * it doesn't starve the system. Threads not behaving properly might
- * be "punished" by the kernel.
- * Use the levels below when appropriate. Intermediate values are
- * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
- */
- ANDROID_PRIORITY_LOWEST = ,
- /** use for background tasks */
- ANDROID_PRIORITY_BACKGROUND = ,
- /** most threads run at normal priority */
- ANDROID_PRIORITY_NORMAL = ,
- /** threads currently running a UI that the user is interacting with */
- ANDROID_PRIORITY_FOREGROUND = -,
- /** the main UI thread has a slightly more favorable priority */
- ANDROID_PRIORITY_DISPLAY = -,
- /** ui service treads might want to run at a urgent display (uncommon) */
- ANDROID_PRIORITY_URGENT_DISPLAY = HAL_PRIORITY_URGENT_DISPLAY,
- /** all normal audio threads */
- ANDROID_PRIORITY_AUDIO = -,
- /** service audio threads (uncommon) */
- ANDROID_PRIORITY_URGENT_AUDIO = -,
- /** should never be used in practice. regular process might not
- * be allowed to use this level */
- ANDROID_PRIORITY_HIGHEST = -,
- ANDROID_PRIORITY_DEFAULT = ANDROID_PRIORITY_NORMAL,
- ANDROID_PRIORITY_MORE_FAVORABLE = -,
- ANDROID_PRIORITY_LESS_FAVORABLE = +,
- };
- enum {
- ANDROID_TGROUP_DEFAULT = ,
- ANDROID_TGROUP_BG_NONINTERACT = ,
- ANDROID_TGROUP_FG_BOOST = ,
- ANDROID_TGROUP_MAX = ANDROID_TGROUP_FG_BOOST,
- };
- // Create and run a new thread.
- extern int androidCreateThread(android_thread_func_t, void *);
- // Create thread with lots of parameters
- extern int androidCreateThreadEtc(android_thread_func_t entryFunction,
- void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t *threadId);
- // Get some sort of unique identifier for the current thread.
- extern android_thread_id_t androidGetThreadId();
- // Low-level thread creation -- never creates threads that can
- // interact with the Java VM.
- extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
- void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t *threadId);
- // Used by the Java Runtime to control how threads are created, so that
- // they can be proper and lovely Java threads.
- typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
- void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t *threadId);
- extern void androidSetCreateThreadFunc(android_create_thread_fn func);
- // ------------------------------------------------------------------
- // Extra functions working with raw pids.
- // Get pid for the current thread.
- extern pid_t androidGetTid();
- // Change the scheduling group of a particular thread. The group
- // should be one of the ANDROID_TGROUP constants. Returns BAD_VALUE if
- // grp is out of range, else another non-zero value with errno set if
- // the operation failed. Thread ID zero means current thread.
- extern int androidSetThreadSchedulingGroup(pid_t tid, int grp);
- // Change the priority AND scheduling group of a particular thread. The priority
- // should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION
- // if the priority set failed, else another value if just the group set failed;
- // in either case errno is set. Thread ID zero means current thread.
- extern int androidSetThreadPriority(pid_t tid, int prio);
- // Get the current priority of a particular thread. Returns one of the
- // ANDROID_PRIORITY constants or a negative result in case of error.
- extern int androidGetThreadPriority(pid_t tid);
- // Get the current scheduling group of a particular thread. Normally returns
- // one of the ANDROID_TGROUP constants other than ANDROID_TGROUP_DEFAULT.
- // Returns ANDROID_TGROUP_DEFAULT if no pthread support (e.g. on host) or if
- // scheduling groups are disabled. Returns INVALID_OPERATION if unexpected error.
- // Thread ID zero means current thread.
- extern int androidGetThreadSchedulingGroup(pid_t tid);
- #ifdef __cplusplus
- }
- #endif
- // ------------------------------------------------------------------
- // C++ API
- #ifdef __cplusplus
- #include <utils/Errors.h>
- #include <utils/RefBase.h>
- #include <utils/Timers.h>
- namespace android {
- typedef android_thread_id_t thread_id_t;
- typedef android_thread_func_t thread_func_t;
- enum {
- PRIORITY_LOWEST = ANDROID_PRIORITY_LOWEST,
- PRIORITY_BACKGROUND = ANDROID_PRIORITY_BACKGROUND,
- PRIORITY_NORMAL = ANDROID_PRIORITY_NORMAL,
- PRIORITY_FOREGROUND = ANDROID_PRIORITY_FOREGROUND,
- PRIORITY_DISPLAY = ANDROID_PRIORITY_DISPLAY,
- PRIORITY_URGENT_DISPLAY = ANDROID_PRIORITY_URGENT_DISPLAY,
- PRIORITY_AUDIO = ANDROID_PRIORITY_AUDIO,
- PRIORITY_URGENT_AUDIO = ANDROID_PRIORITY_URGENT_AUDIO,
- PRIORITY_HIGHEST = ANDROID_PRIORITY_HIGHEST,
- PRIORITY_DEFAULT = ANDROID_PRIORITY_DEFAULT,
- PRIORITY_MORE_FAVORABLE = ANDROID_PRIORITY_MORE_FAVORABLE,
- PRIORITY_LESS_FAVORABLE = ANDROID_PRIORITY_LESS_FAVORABLE,
- };
- // Create and run a new thread.
- inline bool createThread(thread_func_t f, void *a) {
- return androidCreateThread(f, a) ? true : false;
- }
- // Create thread with lots of parameters
- inline bool createThreadEtc(thread_func_t entryFunction,
- void *userData,
- const char* threadName = "android:unnamed_thread",
- int32_t threadPriority = PRIORITY_DEFAULT,
- size_t threadStackSize = ,
- thread_id_t *threadId = )
- {
- return androidCreateThreadEtc(entryFunction, userData, threadName,
- threadPriority, threadStackSize, threadId) ? true : false;
- }
- // Get some sort of unique identifier for the current thread.
- inline thread_id_t getThreadId() {
- return androidGetThreadId();
- }
- /******************************************************************************/
- /**
- * Simple mutex class. The implementation is system-dependent.
- *
- * The mutex must be unlocked by the thread that locked it. They are not
- * recursive, i.e. the same thread can't lock it multiple times.
- */
- class Mutex {
- public:
- enum {
- PRIVATE = ,
- SHARED =
- };
- Mutex();
- Mutex(const char* name);
- Mutex(int type, const char* name = NULL);
- ~Mutex();
- // lock or unlock the mutex
- status_t lock();
- void unlock();
- // lock if possible; returns 0 on success, error otherwise
- status_t tryLock();
- // Manages the mutex automatically. It'll be locked when Autolock is
- // constructed and released when Autolock goes out of scope.
- class Autolock {
- public:
- inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
- inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
- inline ~Autolock() { mLock.unlock(); }
- private:
- Mutex& mLock;
- };
- private:
- friend class Condition;
- // A mutex cannot be copied
- Mutex(const Mutex&);
- Mutex& operator = (const Mutex&);
- #if defined(HAVE_PTHREADS)
- pthread_mutex_t mMutex;
- #else
- void _init();
- void* mState;
- #endif
- };
- #if defined(HAVE_PTHREADS)
- inline Mutex::Mutex() {
- pthread_mutex_init(&mMutex, NULL);
- }
- inline Mutex::Mutex(const char* name) {
- pthread_mutex_init(&mMutex, NULL);
- }
- inline Mutex::Mutex(int type, const char* name) {
- if (type == SHARED) {
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
- pthread_mutex_init(&mMutex, &attr);
- pthread_mutexattr_destroy(&attr);
- } else {
- pthread_mutex_init(&mMutex, NULL);
- }
- }
- inline Mutex::~Mutex() {
- pthread_mutex_destroy(&mMutex);
- }
- inline status_t Mutex::lock() {
- return -pthread_mutex_lock(&mMutex);
- }
- inline void Mutex::unlock() {
- pthread_mutex_unlock(&mMutex);
- }
- inline status_t Mutex::tryLock() {
- return -pthread_mutex_trylock(&mMutex);
- }
- #endif // HAVE_PTHREADS
- /**
- * Automatic mutex. Declare one of these at the top of a function.
- * When the function returns, it will go out of scope, and release the
- * mutex.
- */
- typedef Mutex::Autolock AutoMutex;
- /******************************************************************************/
- #if defined(HAVE_PTHREADS)
- /**
- * Simple mutex class. The implementation is system-dependent.
- *
- * The mutex must be unlocked by the thread that locked it. They are not
- * recursive, i.e. the same thread can't lock it multiple times.
- */
- class RWLock {
- public:
- enum {
- PRIVATE = ,
- SHARED =
- };
- RWLock();
- RWLock(const char* name);
- RWLock(int type, const char* name = NULL);
- ~RWLock();
- status_t readLock();
- status_t tryReadLock();
- status_t writeLock();
- status_t tryWriteLock();
- void unlock();
- class AutoRLock {
- public:
- inline AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); }
- inline ~AutoRLock() { mLock.unlock(); }
- private:
- RWLock& mLock;
- };
- class AutoWLock {
- public:
- inline AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); }
- inline ~AutoWLock() { mLock.unlock(); }
- private:
- RWLock& mLock;
- };
- private:
- // A RWLock cannot be copied
- RWLock(const RWLock&);
- RWLock& operator = (const RWLock&);
- pthread_rwlock_t mRWLock;
- };
- inline RWLock::RWLock() {
- pthread_rwlock_init(&mRWLock, NULL);
- }
- inline RWLock::RWLock(const char* name) {
- pthread_rwlock_init(&mRWLock, NULL);
- }
- inline RWLock::RWLock(int type, const char* name) {
- if (type == SHARED) {
- pthread_rwlockattr_t attr;
- pthread_rwlockattr_init(&attr);
- pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
- pthread_rwlock_init(&mRWLock, &attr);
- pthread_rwlockattr_destroy(&attr);
- } else {
- pthread_rwlock_init(&mRWLock, NULL);
- }
- }
- inline RWLock::~RWLock() {
- pthread_rwlock_destroy(&mRWLock);
- }
- inline status_t RWLock::readLock() {
- return -pthread_rwlock_rdlock(&mRWLock);
- }
- inline status_t RWLock::tryReadLock() {
- return -pthread_rwlock_tryrdlock(&mRWLock);
- }
- inline status_t RWLock::writeLock() {
- return -pthread_rwlock_wrlock(&mRWLock);
- }
- inline status_t RWLock::tryWriteLock() {
- return -pthread_rwlock_trywrlock(&mRWLock);
- }
- inline void RWLock::unlock() {
- pthread_rwlock_unlock(&mRWLock);
- }
- #endif // HAVE_PTHREADS
- /******************************************************************************/
- /**
- * Condition variable class. The implementation is system-dependent.
- *
- * Condition variables are paired up with mutexes. Lock the mutex,
- * call wait(), then either re-wait() if things aren't quite what you want,
- * or unlock the mutex and continue. All threads calling wait() must
- * use the same mutex for a given Condition.
- */
- class Condition {
- public:
- enum {
- PRIVATE = ,
- SHARED =
- };
- Condition();
- Condition(int type);
- ~Condition();
- // Wait on the condition variable. Lock the mutex before calling.
- status_t wait(Mutex& mutex);
- // same with relative timeout
- status_t waitRelative(Mutex& mutex, nsecs_t reltime);
- // Signal the condition variable, allowing one thread to continue.
- void signal();
- // Signal the condition variable, allowing all threads to continue.
- void broadcast();
- private:
- #if defined(HAVE_PTHREADS)
- pthread_cond_t mCond;
- #else
- void* mState;
- #endif
- };
- #if defined(HAVE_PTHREADS)
- inline Condition::Condition() {
- pthread_cond_init(&mCond, NULL);
- }
- inline Condition::Condition(int type) {
- if (type == SHARED) {
- pthread_condattr_t attr;
- pthread_condattr_init(&attr);
- pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
- pthread_cond_init(&mCond, &attr);
- pthread_condattr_destroy(&attr);
- } else {
- pthread_cond_init(&mCond, NULL);
- }
- }
- inline Condition::~Condition() {
- pthread_cond_destroy(&mCond);
- }
- inline status_t Condition::wait(Mutex& mutex) {
- return -pthread_cond_wait(&mCond, &mutex.mMutex);
- }
- inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
- #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
- struct timespec ts;
- ts.tv_sec = reltime/;
- ts.tv_nsec = reltime%;
- return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
- #else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
- struct timespec ts;
- #if defined(HAVE_POSIX_CLOCKS)
- clock_gettime(CLOCK_REALTIME, &ts);
- #else // HAVE_POSIX_CLOCKS
- // we don't support the clocks here.
- struct timeval t;
- gettimeofday(&t, NULL);
- ts.tv_sec = t.tv_sec;
- ts.tv_nsec= t.tv_usec*;
- #endif // HAVE_POSIX_CLOCKS
- ts.tv_sec += reltime/;
- ts.tv_nsec+= reltime%;
- if (ts.tv_nsec >= ) {
- ts.tv_nsec -= ;
- ts.tv_sec += ;
- }
- return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
- #endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
- }
- inline void Condition::signal() {
- pthread_cond_signal(&mCond);
- }
- inline void Condition::broadcast() {
- pthread_cond_broadcast(&mCond);
- }
- #endif // HAVE_PTHREADS
- /******************************************************************************/
- /**
- * This is our spiffy thread object!
- */
- class Thread : virtual public RefBase
- {
- public:
- // Create a Thread object, but doesn't create or start the associated
- // thread. See the run() method.
- Thread(bool canCallJava = true);
- virtual ~Thread();
- // Start the thread in threadLoop() which needs to be implemented.
- virtual status_t run( const char* name = ,
- int32_t priority = PRIORITY_DEFAULT,
- size_t stack = );
- // Ask this object's thread to exit. This function is asynchronous, when the
- // function returns the thread might still be running. Of course, this
- // function can be called from a different thread.
- virtual void requestExit();
- // Good place to do one-time initializations
- virtual status_t readyToRun();
- // Call requestExit() and wait until this object's thread exits.
- // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
- // this function from this object's thread. Will return WOULD_BLOCK in
- // that case.
- status_t requestExitAndWait();
- // Wait until this object's thread exits. Returns immediately if not yet running.
- // Do not call from this object's thread; will return WOULD_BLOCK in that case.
- status_t join();
- protected:
- // exitPending() returns true if requestExit() has been called.
- bool exitPending() const;
- private:
- // Derived class must implement threadLoop(). The thread starts its life
- // here. There are two ways of using the Thread object:
- // 1) loop: if threadLoop() returns true, it will be called again if
- // requestExit() wasn't called.
- // 2) once: if threadLoop() returns false, the thread will exit upon return.
- virtual bool threadLoop() = ;
- private:
- Thread& operator=(const Thread&);
- static int _threadLoop(void* user);
- const bool mCanCallJava;
- // always hold mLock when reading or writing
- thread_id_t mThread;
- mutable Mutex mLock;
- Condition mThreadExitedCondition;
- status_t mStatus;
- // note that all accesses of mExitPending and mRunning need to hold mLock
- volatile bool mExitPending;
- volatile bool mRunning;
- sp<Thread> mHoldSelf;
- #if HAVE_ANDROID_OS
- int mTid;
- #endif
- };
- }; // namespace android
- #endif // __cplusplus
- #endif // _LIBS_UTILS_THREADS_H
threads.h
- /**
- /**
- * Copyright (C) 2007 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.
- */
- // #define LOG_NDEBUG 0
- #define LOG_TAG "libutils.threads"
- #include <utils/threads.h>
- #include <utils/Log.h>
- #include <cutils/sched_policy.h>
- #include <cutils/properties.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory.h>
- #include <errno.h>
- #include <assert.h>
- #include <unistd.h>
- #if defined(HAVE_PTHREADS)
- # include <pthread.h>
- # include <sched.h>
- # include <sys/resource.h>
- #elif defined(HAVE_WIN32_THREADS)
- # include <windows.h>
- # include <stdint.h>
- # include <process.h>
- # define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
- #endif
- #if defined(HAVE_PRCTL)
- #include <sys/prctl.h>
- #endif
- /**
- * ===========================================================================
- * Thread wrappers
- * ===========================================================================
- */
- using namespace android;
- // ----------------------------------------------------------------------------
- #if defined(HAVE_PTHREADS)
- // ----------------------------------------------------------------------------
- /**
- * Create and run a new thread.
- *
- * We create it "detached", so it cleans up after itself.
- */
- typedef void* (*android_pthread_entry)(void*);
- static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT;
- static bool gDoSchedulingGroup = true;
- static void checkDoSchedulingGroup(void) {
- char buf[PROPERTY_VALUE_MAX];
- int len = property_get("debug.sys.noschedgroups", buf, "");
- if (len > ) {
- int temp;
- if (sscanf(buf, "%d", &temp) == ) {
- gDoSchedulingGroup = temp == ;
- }
- }
- }
- struct thread_data_t {
- thread_func_t entryFunction;
- void* userData;
- int priority;
- char * threadName;
- // we use this trampoline when we need to set the priority with
- // nice/setpriority.
- static int trampoline(const thread_data_t* t) {
- thread_func_t f = t->entryFunction;
- void* u = t->userData;
- int prio = t->priority;
- char * name = t->threadName;
- delete t;
- setpriority(PRIO_PROCESS, , prio);
- pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
- if (gDoSchedulingGroup) {
- if (prio >= ANDROID_PRIORITY_BACKGROUND) {
- set_sched_policy(androidGetTid(), SP_BACKGROUND);
- } else {
- set_sched_policy(androidGetTid(), SP_FOREGROUND);
- }
- }
- if (name) {
- #if defined(HAVE_PRCTL)
- // Mac OS doesn't have this, and we build libutil for the host too
- int hasAt = ;
- int hasDot = ;
- char *s = name;
- while (*s) {
- if (*s == '.') hasDot = ;
- else if (*s == '@') hasAt = ;
- s++;
- }
- int len = s - name;
- if (len < || hasAt || !hasDot) {
- s = name;
- } else {
- s = name + len - ;
- }
- prctl(PR_SET_NAME, (unsigned long) s, , , );
- #endif
- free(name);
- }
- return f(u);
- }
- };
- int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
- void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t *threadId)
- {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- #ifdef HAVE_ANDROID_OS /** valgrind is rejecting RT-priority create reqs */
- if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
- // We could avoid the trampoline if there was a way to get to the
- // android_thread_id_t (pid) from pthread_t
- thread_data_t* t = new thread_data_t;
- t->priority = threadPriority;
- t->threadName = threadName ? strdup(threadName) : NULL;
- t->entryFunction = entryFunction;
- t->userData = userData;
- entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
- userData = t;
- }
- #endif
- if (threadStackSize) {
- pthread_attr_setstacksize(&attr, threadStackSize);
- }
- errno = ;
- pthread_t thread;
- int result = pthread_create(&thread, &attr,
- (android_pthread_entry)entryFunction, userData);
- pthread_attr_destroy(&attr);
- if (result != ) {
- LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
- "(android threadPriority=%d)",
- entryFunction, result, errno, threadPriority);
- return ;
- }
- // Note that *threadID is directly available to the parent only, as it is
- // assigned after the child starts. Use memory barrier / lock if the child
- // or other threads also need access.
- if (threadId != NULL) {
- *threadId = (android_thread_id_t)thread; // XXX: this is not portable
- }
- return ;
- }
- android_thread_id_t androidGetThreadId()
- {
- return (android_thread_id_t)pthread_self();
- }
- // ----------------------------------------------------------------------------
- #elif defined(HAVE_WIN32_THREADS)
- // ----------------------------------------------------------------------------
- /**
- * Trampoline to make us __stdcall-compliant.
- *
- * We're expected to delete "vDetails" when we're done.
- */
- struct threadDetails {
- int (*func)(void*);
- void* arg;
- };
- static __stdcall unsigned int threadIntermediary(void* vDetails)
- {
- struct threadDetails* pDetails = (struct threadDetails*) vDetails;
- int result;
- result = (*(pDetails->func))(pDetails->arg);
- delete pDetails;
- LOG(LOG_VERBOSE, "thread", "thread exiting\n");
- return (unsigned int) result;
- }
- /**
- * Create and run a new thread.
- */
- static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id)
- {
- HANDLE hThread;
- struct threadDetails* pDetails = new threadDetails; // must be on heap
- unsigned int thrdaddr;
- pDetails->func = fn;
- pDetails->arg = arg;
- #if defined(HAVE__BEGINTHREADEX)
- hThread = (HANDLE) _beginthreadex(NULL, , threadIntermediary, pDetails, ,
- &thrdaddr);
- if (hThread == )
- #elif defined(HAVE_CREATETHREAD)
- hThread = CreateThread(NULL, ,
- (LPTHREAD_START_ROUTINE) threadIntermediary,
- (void*) pDetails, , (DWORD*) &thrdaddr);
- if (hThread == NULL)
- #endif
- {
- LOG(LOG_WARN, "thread", "WARNING: thread create failed\n");
- return false;
- }
- #if defined(HAVE_CREATETHREAD)
- /** close the management handle */
- CloseHandle(hThread);
- #endif
- if (id != NULL) {
- *id = (android_thread_id_t)thrdaddr;
- }
- return true;
- }
- int androidCreateRawThreadEtc(android_thread_func_t fn,
- void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t *threadId)
- {
- return doCreateThread( fn, userData, threadId);
- }
- android_thread_id_t androidGetThreadId()
- {
- return (android_thread_id_t)GetCurrentThreadId();
- }
- // ----------------------------------------------------------------------------
- #else
- #error "Threads not supported"
- #endif
- // ----------------------------------------------------------------------------
- int androidCreateThread(android_thread_func_t fn, void* arg)
- {
- return createThreadEtc(fn, arg);
- }
- int androidCreateThreadGetID(android_thread_func_t fn, void *arg, android_thread_id_t *id)
- {
- return createThreadEtc(fn, arg, "android:unnamed_thread",
- PRIORITY_DEFAULT, , id);
- }
- static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
- int androidCreateThreadEtc(android_thread_func_t entryFunction,
- void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t *threadId)
- {
- return gCreateThreadFn(entryFunction, userData, threadName,
- threadPriority, threadStackSize, threadId);
- }
- void androidSetCreateThreadFunc(android_create_thread_fn func)
- {
- gCreateThreadFn = func;
- }
- pid_t androidGetTid()
- {
- #ifdef HAVE_GETTID
- return gettid();
- #else
- return getpid();
- #endif
- }
- int androidSetThreadSchedulingGroup(pid_t tid, int grp)
- {
- if (grp > ANDROID_TGROUP_MAX || grp < ) {
- return BAD_VALUE;
- }
- #if defined(HAVE_PTHREADS)
- pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
- if (gDoSchedulingGroup) {
- // set_sched_policy does not support tid == 0
- if (tid == ) {
- tid = androidGetTid();
- }
- if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
- SP_BACKGROUND : SP_FOREGROUND)) {
- return PERMISSION_DENIED;
- }
- }
- #endif
- return NO_ERROR;
- }
- int androidSetThreadPriority(pid_t tid, int pri)
- {
- int rc = ;
- #if defined(HAVE_PTHREADS)
- int lasterr = ;
- pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
- if (gDoSchedulingGroup) {
- // set_sched_policy does not support tid == 0
- int policy_tid;
- if (tid == ) {
- policy_tid = androidGetTid();
- } else {
- policy_tid = tid;
- }
- if (pri >= ANDROID_PRIORITY_BACKGROUND) {
- rc = set_sched_policy(policy_tid, SP_BACKGROUND);
- } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
- rc = set_sched_policy(policy_tid, SP_FOREGROUND);
- }
- }
- if (rc) {
- lasterr = errno;
- }
- if (setpriority(PRIO_PROCESS, tid, pri) < ) {
- rc = INVALID_OPERATION;
- } else {
- errno = lasterr;
- }
- #endif
- return rc;
- }
- int androidGetThreadPriority(pid_t tid) {
- #if defined(HAVE_PTHREADS)
- return getpriority(PRIO_PROCESS, tid);
- #else
- return ANDROID_PRIORITY_NORMAL;
- #endif
- }
- int androidGetThreadSchedulingGroup(pid_t tid)
- {
- int ret = ANDROID_TGROUP_DEFAULT;
- #if defined(HAVE_PTHREADS)
- // convention is to not call get/set_sched_policy methods if disabled by property
- pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
- if (gDoSchedulingGroup) {
- SchedPolicy policy;
- // get_sched_policy does not support tid == 0
- if (tid == ) {
- tid = androidGetTid();
- }
- if (get_sched_policy(tid, &policy) < ) {
- ret = INVALID_OPERATION;
- } else {
- switch (policy) {
- case SP_BACKGROUND:
- ret = ANDROID_TGROUP_BG_NONINTERACT;
- break;
- case SP_FOREGROUND:
- ret = ANDROID_TGROUP_FG_BOOST;
- break;
- default:
- // should not happen, as enum SchedPolicy does not have any other values
- ret = INVALID_OPERATION;
- break;
- }
- }
- }
- #endif
- return ret;
- }
- namespace android {
- /**
- * ===========================================================================
- * Mutex class
- * ===========================================================================
- */
- #if defined(HAVE_PTHREADS)
- // implemented as inlines in threads.h
- #elif defined(HAVE_WIN32_THREADS)
- Mutex::Mutex()
- {
- HANDLE hMutex;
- assert(sizeof(hMutex) == sizeof(mState));
- hMutex = CreateMutex(NULL, FALSE, NULL);
- mState = (void*) hMutex;
- }
- Mutex::Mutex(const char* name)
- {
- // XXX: name not used for now
- HANDLE hMutex;
- assert(sizeof(hMutex) == sizeof(mState));
- hMutex = CreateMutex(NULL, FALSE, NULL);
- mState = (void*) hMutex;
- }
- Mutex::Mutex(int type, const char* name)
- {
- // XXX: type and name not used for now
- HANDLE hMutex;
- assert(sizeof(hMutex) == sizeof(mState));
- hMutex = CreateMutex(NULL, FALSE, NULL);
- mState = (void*) hMutex;
- }
- Mutex::~Mutex()
- {
- CloseHandle((HANDLE) mState);
- }
- status_t Mutex::lock()
- {
- DWORD dwWaitResult;
- dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
- return dwWaitResult != WAIT_OBJECT_0 ? - : NO_ERROR;
- }
- void Mutex::unlock()
- {
- if (!ReleaseMutex((HANDLE) mState))
- LOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex\n");
- }
- status_t Mutex::tryLock()
- {
- DWORD dwWaitResult;
- dwWaitResult = WaitForSingleObject((HANDLE) mState, );
- if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT)
- LOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex\n");
- return (dwWaitResult == WAIT_OBJECT_0) ? : -;
- }
- #else
- #error "Somebody forgot to implement threads for this platform."
- #endif
- /**
- * ===========================================================================
- * Condition class
- * ===========================================================================
- */
- #if defined(HAVE_PTHREADS)
- // implemented as inlines in threads.h
- #elif defined(HAVE_WIN32_THREADS)
- /**
- * Windows doesn't have a condition variable solution. It's possible
- * to create one, but it's easy to get it wrong. For a discussion, and
- * the origin of this implementation, see:
- *
- * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
- *
- * The implementation shown on the page does NOT follow POSIX semantics.
- * As an optimization they require acquiring the external mutex before
- * calling signal() and broadcast(), whereas POSIX only requires grabbing
- * it before calling wait(). The implementation here has been un-optimized
- * to have the correct behavior.
- */
- typedef struct WinCondition {
- // Number of waiting threads.
- int waitersCount;
- // Serialize access to waitersCount.
- CRITICAL_SECTION waitersCountLock;
- // Semaphore used to queue up threads waiting for the condition to
- // become signaled.
- HANDLE sema;
- // An auto-reset event used by the broadcast/signal thread to wait
- // for all the waiting thread(s) to wake up and be released from
- // the semaphore.
- HANDLE waitersDone;
- // This mutex wouldn't be necessary if we required that the caller
- // lock the external mutex before calling signal() and broadcast().
- // I'm trying to mimic pthread semantics though.
- HANDLE internalMutex;
- // Keeps track of whether we were broadcasting or signaling. This
- // allows us to optimize the code if we're just signaling.
- bool wasBroadcast;
- status_t wait(WinCondition* condState, HANDLE hMutex, nsecs_t* abstime)
- {
- // Increment the wait count, avoiding race conditions.
- EnterCriticalSection(&condState->waitersCountLock);
- condState->waitersCount++;
- //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n",
- // condState->waitersCount, getThreadId());
- LeaveCriticalSection(&condState->waitersCountLock);
- DWORD timeout = INFINITE;
- if (abstime) {
- nsecs_t reltime = *abstime - systemTime();
- if (reltime < )
- reltime = ;
- timeout = reltime/;
- }
- // Atomically release the external mutex and wait on the semaphore.
- DWORD res =
- SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE);
- //printf("+++ wait: awake (tid=%ld)\n", getThreadId());
- // Reacquire lock to avoid race conditions.
- EnterCriticalSection(&condState->waitersCountLock);
- // No longer waiting.
- condState->waitersCount--;
- // Check to see if we're the last waiter after a broadcast.
- bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == );
- //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n",
- // lastWaiter, condState->wasBroadcast, condState->waitersCount);
- LeaveCriticalSection(&condState->waitersCountLock);
- // If we're the last waiter thread during this particular broadcast
- // then signal broadcast() that we're all awake. It'll drop the
- // internal mutex.
- if (lastWaiter) {
- // Atomically signal the "waitersDone" event and wait until we
- // can acquire the internal mutex. We want to do this in one step
- // because it ensures that everybody is in the mutex FIFO before
- // any thread has a chance to run. Without it, another thread
- // could wake up, do work, and hop back in ahead of us.
- SignalObjectAndWait(condState->waitersDone, condState->internalMutex,
- INFINITE, FALSE);
- } else {
- // Grab the internal mutex.
- WaitForSingleObject(condState->internalMutex, INFINITE);
- }
- // Release the internal and grab the external.
- ReleaseMutex(condState->internalMutex);
- WaitForSingleObject(hMutex, INFINITE);
- return res == WAIT_OBJECT_0 ? NO_ERROR : -;
- }
- } WinCondition;
- /**
- * Constructor. Set up the WinCondition stuff.
- */
- Condition::Condition()
- {
- WinCondition* condState = new WinCondition;
- condState->waitersCount = ;
- condState->wasBroadcast = false;
- // semaphore: no security, initial value of 0
- condState->sema = CreateSemaphore(NULL, , 0x7fffffff, NULL);
- InitializeCriticalSection(&condState->waitersCountLock);
- // auto-reset event, not signaled initially
- condState->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
- // used so we don't have to lock external mutex on signal/broadcast
- condState->internalMutex = CreateMutex(NULL, FALSE, NULL);
- mState = condState;
- }
- /**
- * Destructor. Free Windows resources as well as our allocated storage.
- */
- Condition::~Condition()
- {
- WinCondition* condState = (WinCondition*) mState;
- if (condState != NULL) {
- CloseHandle(condState->sema);
- CloseHandle(condState->waitersDone);
- delete condState;
- }
- }
- status_t Condition::wait(Mutex& mutex)
- {
- WinCondition* condState = (WinCondition*) mState;
- HANDLE hMutex = (HANDLE) mutex.mState;
- return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
- }
- status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
- {
- WinCondition* condState = (WinCondition*) mState;
- HANDLE hMutex = (HANDLE) mutex.mState;
- nsecs_t absTime = systemTime()+reltime;
- return ((WinCondition*)mState)->wait(condState, hMutex, &absTime);
- }
- /**
- * Signal the condition variable, allowing one thread to continue.
- */
- void Condition::signal()
- {
- WinCondition* condState = (WinCondition*) mState;
- // Lock the internal mutex. This ensures that we don't clash with
- // broadcast().
- WaitForSingleObject(condState->internalMutex, INFINITE);
- EnterCriticalSection(&condState->waitersCountLock);
- bool haveWaiters = (condState->waitersCount > );
- LeaveCriticalSection(&condState->waitersCountLock);
- // If no waiters, then this is a no-op. Otherwise, knock the semaphore
- // down a notch.
- if (haveWaiters)
- ReleaseSemaphore(condState->sema, , );
- // Release internal mutex.
- ReleaseMutex(condState->internalMutex);
- }
- /**
- * Signal the condition variable, allowing all threads to continue.
- *
- * First we have to wake up all threads waiting on the semaphore, then
- * we wait until all of the threads have actually been woken before
- * releasing the internal mutex. This ensures that all threads are woken.
- */
- void Condition::broadcast()
- {
- WinCondition* condState = (WinCondition*) mState;
- // Lock the internal mutex. This keeps the guys we're waking up
- // from getting too far.
- WaitForSingleObject(condState->internalMutex, INFINITE);
- EnterCriticalSection(&condState->waitersCountLock);
- bool haveWaiters = false;
- if (condState->waitersCount > ) {
- haveWaiters = true;
- condState->wasBroadcast = true;
- }
- if (haveWaiters) {
- // Wake up all the waiters.
- ReleaseSemaphore(condState->sema, condState->waitersCount, );
- LeaveCriticalSection(&condState->waitersCountLock);
- // Wait for all awakened threads to acquire the counting semaphore.
- // The last guy who was waiting sets this.
- WaitForSingleObject(condState->waitersDone, INFINITE);
- // Reset wasBroadcast. (No crit section needed because nobody
- // else can wake up to poke at it.)
- condState->wasBroadcast = ;
- } else {
- // nothing to do
- LeaveCriticalSection(&condState->waitersCountLock);
- }
- // Release internal mutex.
- ReleaseMutex(condState->internalMutex);
- }
- #else
- #error "condition variables not supported on this platform"
- #endif
- // ----------------------------------------------------------------------------
- /**
- * This is our thread object!
- */
- Thread::Thread(bool canCallJava)
- : mCanCallJava(canCallJava),
- mThread(thread_id_t(-)),
- mLock("Thread::mLock"),
- mStatus(NO_ERROR),
- mExitPending(false), mRunning(false)
- #ifdef HAVE_ANDROID_OS
- , mTid(-)
- #endif
- {
- }
- Thread::~Thread()
- {
- }
- status_t Thread::readyToRun()
- {
- return NO_ERROR;
- }
- status_t Thread::run(const char* name, int32_t priority, size_t stack)
- {
- Mutex::Autolock _l(mLock);
- if (mRunning) {
- // thread already started
- return INVALID_OPERATION;
- }
- // reset status and exitPending to their default value, so we can
- // try again after an error happened (either below, or in readyToRun())
- mStatus = NO_ERROR;
- mExitPending = false;
- mThread = thread_id_t(-);
- // hold a strong reference on ourself
- mHoldSelf = this;
- mRunning = true;
- bool res;
- if (mCanCallJava) {
- res = createThreadEtc(_threadLoop,
- this, name, priority, stack, &mThread);
- } else {
- res = androidCreateRawThreadEtc(_threadLoop,
- this, name, priority, stack, &mThread);
- }
- if (res == false) {
- mStatus = UNKNOWN_ERROR; // something happened!
- mRunning = false;
- mThread = thread_id_t(-);
- mHoldSelf.clear(); // "this" may have gone away after this.
- return UNKNOWN_ERROR;
- }
- // Do not refer to mStatus here: The thread is already running (may, in fact
- // already have exited with a valid mStatus result). The NO_ERROR indication
- // here merely indicates successfully starting the thread and does not
- // imply successful termination/execution.
- return NO_ERROR;
- // Exiting scope of mLock is a memory barrier and allows new thread to run
- }
- int Thread::_threadLoop(void* user)
- {
- Thread* const self = static_cast<Thread*>(user);
- sp<Thread> strong(self->mHoldSelf);
- wp<Thread> weak(strong);
- self->mHoldSelf.clear();
- #ifdef HAVE_ANDROID_OS
- // this is very useful for debugging with gdb
- self->mTid = gettid();
- #endif
- bool first = true;
- do {
- bool result;
- if (first) {
- first = false;
- self->mStatus = self->readyToRun();
- result = (self->mStatus == NO_ERROR);
- if (result && !self->exitPending()) {
- // Binder threads (and maybe others) rely on threadLoop
- // running at least once after a successful ::readyToRun()
- // (unless, of course, the thread has already been asked to exit
- // at that point).
- // This is because threads are essentially used like this:
- // (new ThreadSubclass())->run();
- // The caller therefore does not retain a strong reference to
- // the thread and the thread would simply disappear after the
- // successful ::readyToRun() call instead of entering the
- // threadLoop at least once.
- result = self->threadLoop();
- }
- } else {
- result = self->threadLoop();
- }
- // establish a scope for mLock
- {
- Mutex::Autolock _l(self->mLock);
- if (result == false || self->mExitPending) {
- self->mExitPending = true;
- self->mRunning = false;
- // clear thread ID so that requestExitAndWait() does not exit if
- // called by a new thread using the same thread ID as this one.
- self->mThread = thread_id_t(-);
- // note that interested observers blocked in requestExitAndWait are
- // awoken by broadcast, but blocked on mLock until break exits scope
- self->mThreadExitedCondition.broadcast();
- break;
- }
- }
- // Release our strong reference, to let a chance to the thread
- // to die a peaceful death.
- strong.clear();
- // And immediately, re-acquire a strong reference for the next loop
- strong = weak.promote();
- } while(strong != );
- return ;
- }
- void Thread::requestExit()
- {
- Mutex::Autolock _l(mLock);
- mExitPending = true;
- }
- status_t Thread::requestExitAndWait()
- {
- Mutex::Autolock _l(mLock);
- if (mThread == getThreadId()) {
- LOGW(
- "Thread (this=%p): don't call waitForExit() from this "
- "Thread object's thread. It's a guaranteed deadlock!",
- this);
- return WOULD_BLOCK;
- }
- mExitPending = true;
- while (mRunning == true) {
- mThreadExitedCondition.wait(mLock);
- }
- // This next line is probably not needed any more, but is being left for
- // historical reference. Note that each interested party will clear flag.
- mExitPending = false;
- return mStatus;
- }
- status_t Thread::join()
- {
- Mutex::Autolock _l(mLock);
- if (mThread == getThreadId()) {
- LOGW(
- "Thread (this=%p): don't call join() from this "
- "Thread object's thread. It's a guaranteed deadlock!",
- this);
- return WOULD_BLOCK;
- }
- while (mRunning == true) {
- mThreadExitedCondition.wait(mLock);
- }
- return mStatus;
- }
- bool Thread::exitPending() const
- {
- Mutex::Autolock _l(mLock);
- return mExitPending;
- }
- }; // namespace android
Threads.cpp
- /**
- The definition of Mutex in thread
class Mutex {
public:
enum {
PRIVATE = ,
SHARED =
};
Mutex();
Mutex(const char* name);
Mutex(int type, const char* name = NULL);
~Mutex();
status_t lock();
void unlock();
status_t tryLock();
class Autolock {
public:
inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
private:
friend class Condition;
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex& operator = (const Mutex&);
#if defined(HAVE_PTHREADS)
pthread_mutex_t mMutex;
#else
void _init();
void* mState;
#endif
};
#if defined(HAVE_PTHREADS)
inline Mutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(const char* name) {
pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(int type, const char* name) {
if (type == SHARED) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&mMutex, &attr);
pthread_mutexattr_destroy(&attr);
} else {
pthread_mutex_init(&mMutex, NULL);
}
}
inline Mutex::~Mutex() {
pthread_mutex_destroy(&mMutex);
}
inline status_t Mutex::lock() {
return -pthread_mutex_lock(&mMutex);
}
inline void Mutex::unlock() {
pthread_mutex_unlock(&mMutex);
}
inline status_t Mutex::tryLock() {
return -pthread_mutex_trylock(&mMutex);
}
#endif // HAVE_PTHREADS
typedef Mutex::Autolock AutoMutex;Mutex
- The interface of thread
lass Thread : virtual public RefBase
{
public:
Thread(bool canCallJava = true);
virtual ~Thread();
virtual status_t run(const char* name = ,
int32_t priority = PRIORITY_DEFAULT,
size_t stack = );
virtual void requestExit();ns
virtual status_t readyToRun();
status_t requestExitAndWait();
status_t join();
protected:
bool exitPending() const;
private:
virtual bool threadLoop() = ;
private:
Thread& operator=(const Thread&);
static int _threadLoop(void* user);
const bool mCanCallJava;
thread_id_t mThread;
mutable Mutex mLock;
Condition mThreadExitedCondition;
status_t mStatus;
volatile bool mExitPending;
volatile bool mRunning;
sp<Thread> mHoldSelf;
#if HAVE_ANDROID_OS
int mTid;
#endif
};Thread
- Create a thread on linux as global function
1 inline bool createThread(thread_func_t f, void *a) {
2 return androidCreateThread(f, a) ? true : false;
3 }
4 int androidCreateThread(android_thread_func_t fn, void* arg)
5 {
6 return createThreadEtc(fn, arg);
7 }
8
9 // Create thread with lots of parameters
10 inline bool createThreadEtc(thread_func_t entryFunction,
11 void *userData,
12 const char* threadName = "android:unnamed_thread",
13 int32_t threadPriority = PRIORITY_DEFAULT,
14 size_t threadStackSize = 0,
15 thread_id_t *threadId = 0)
16 {
17 return androidCreateThreadEtc(entryFunction, userData, threadName,
18 threadPriority, threadStackSize, threadId) ? true : false;
19 }
20 static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
21 int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
22 void *userData,
23 const char* threadName,
24 int32_t threadPriority,
25 size_t threadStackSize,
26 android_thread_id_t *threadId)
27 {
28 pthread_attr_t attr;
29 pthread_attr_init(&attr);
30 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
31 #ifdef HAVE_ANDROID_OS /** valgrind is rejecting RT-priority create reqs */
32 if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
33 // We could avoid the trampoline if there was a way to get to the
34 // android_thread_id_t (pid) from pthread_t
35 thread_data_t* t = new thread_data_t;
36 t->priority = threadPriority;
37 t->threadName = threadName ? strdup(threadName) : NULL;
38 t->entryFunction = entryFunction;
39 t->userData = userData;
40 entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
41 userData = t;
42 }
43 #endif
44 if (threadStackSize) {
45 pthread_attr_setstacksize(&attr, threadStackSize);
46 }
47 errno = 0;
48 pthread_t thread;
49 int result = pthread_create(&thread, &attr,android_pthread_entry)entryFunction, userData);
50 pthread_attr_destroy(&attr);
51 if (result != 0) {
52 LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
53 "(android threadPriority=%d)",
54 entryFunction, result, errno, threadPriority);
55 return 0;
56 }
57 // Note that *threadID is directly available to the parent only, as it is
58 // assigned after the child starts. Use memory barrier / lock if the child
59 // or other threads also need access.
60 if (threadId != NULL) {
61 *threadId = (android_thread_id_t)thread; // XXX: this is not portable
62 }
63 return 1;
64 }- Create a new thread on win32 as global function
int androidCreateRawThreadEtc(android_thread_func_t fn,
void *userData,
const char* threadName,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId)
{
return doCreateThread( fn, userData, threadId);
}
static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id)
{
HANDLE hThread;
struct threadDetails* pDetails = new threadDetails; // must be on heap
unsigned int thrdaddr;
pDetails->func = fn;
pDetails->arg = arg;
#if defined(HAVE__BEGINTHREADEX)
hThread = (HANDLE) _beginthreadex(NULL, , threadIntermediary, pDetails, ,&thrdaddr);
if (hThread == )
#elif defined(HAVE_CREATETHREAD)
hThread = CreateThread(NULL, ,LPTHREAD_START_ROUTINE) threadIntermediary,
(void*) pDetails, , (DWORD*) &thrdaddr);
if (hThread == NULL)
#endif
{
LOG(LOG_WARN, "thread", "WARNING: thread create failed\n");
return false;
}
#if defined(HAVE_CREATETHREAD)
/** close the management handle */
CloseHandle(hThread);
#endif
if (id != NULL) {
*id = (android_thread_id_t)thrdaddr;
}
return true;
}- Create a thead in thread object
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
if (mRunning) {
// thread already started
return INVALID_OPERATION;
})
mStatus = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-);
mHoldSelf = this;
mRunning = true;
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-);
mHoldSelf.clear(); // "this" may have gone away after this. return UNKNOWN_ERROR;
}
return NO_ERROR;
}
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast<Thread*>(user);
sp<Thread> strong(self->mHoldSelf);
wp<Thread> weak(strong);
self->mHoldSelf.clear();
#ifdef HAVE_ANDROID_OS
// this is very useful for debugging with gdb
self->mTid = gettid();
#endif
bool first = true; do {
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR); if (result && !self->exitPending()) {
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}
// establish a scope for mLock
{
Mutex::Autolock _l(self->mLock);
if (result == false || self->mExitPending) {
self->mExitPending = true;
self->mRunning = false;
// clear thread ID so that requestExitAndWait() does not exit if
// called by a new thread using the same thread ID as this one.
self->mThread = thread_id_t(-);
// note that interested observers blocked in requestExitAndWait are
// awoken by broadcast, but blocked on mLock until break exits scope
self->mThreadExitedCondition.broadcast();
break;
}
}
strong.clear();
strong = weak.promote();
} while(strong != );
return ;
}
ProcessState
- ProcessState.h
/**
* Copyright (C) 2005 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 ANDROID_PROCESS_STATE_H
#define ANDROID_PROCESS_STATE_H #include <binder/IBinder.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/String16.h> #include <utils/threads.h> // ---------------------------------------------------------------------------
namespace android { // Global variables
extern int mArgC;
extern const char* const* mArgV;
extern int mArgLen; class IPCThreadState; class ProcessState : public virtual RefBase
{
public:
static sp<ProcessState> self();
void setContextObject(const sp<IBinder>& object);
sp<IBinder> getContextObject(const sp<IBinder>& caller);
void setContextObject(const sp<IBinder>& object,
const String16& name);
sp<IBinder> getContextObject(const String16& name,
const sp<IBinder>& caller); void startThreadPool();
typedef bool (*context_check_func)(const String16& name,
const sp<IBinder>& caller,
void* userData); bool isContextManager(void) const;
bool becomeContextManager(
context_check_func checkFunc,
void* userData); sp<IBinder> getStrongProxyForHandle(int32_t handle);
wp<IBinder> getWeakProxyForHandle(int32_t handle);
void expungeHandle(int32_t handle, IBinder* binder); void setArgs(int argc, const char* const argv[]);
int getArgC() const;
const char* const* getArgV() const; void setArgV0(const char* txt); void spawnPooledThread(bool isMain); private:
friend class IPCThreadState; ProcessState();
~ProcessState(); ProcessState(const ProcessState& o);
ProcessState& operator=(const ProcessState& o); struct handle_entry {
IBinder* binder;
RefBase::weakref_type* refs;
}; handle_entry* lookupHandleLocked(int32_t handle); int mDriverFD;
void* mVMStart; mutable Mutex mLock; // protects everything below. Vector<handle_entry>mHandleToObject; bool mManagesContexts;
context_check_func mBinderContextCheckFunc;
void* mBinderContextUserData; KeyedVector<String16, sp<IBinder> >
mContexts; String8 mRootDir;
bool mThreadPoolStarted;
volatile int32_t mThreadPoolSeq;
}; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_PROCESS_STATE_HProcessState.h
- ProcessState.cpp
/**
* Copyright (C) 2005 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.
*/ #define LOG_TAG "ProcessState" #include <cutils/process_name.h> #include <binder/ProcessState.h> #include <utils/Atomic.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <utils/threads.h> #include <private/binder/binder_module.h>
#include <private/binder/Static.h> #include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h> #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) // --------------------------------------------------------------------------- namespace android { // Global variables
int mArgC;
const char* const* mArgV;
int mArgLen; class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
} protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
}; sp<ProcessState> ProcessState::self()
{
if (gProcess != NULL) return gProcess; AutoMutex _l(gProcessMutex);
if (gProcess == NULL) gProcess = new ProcessState;
return gProcess;
} void ProcessState::setContextObject(const sp<IBinder>& object)
{
setContextObject(object, String16("default"));
} sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
return getStrongProxyForHandle();
} void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
{
AutoMutex _l(mLock);
mContexts.add(name, object);
} sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
{
mLock.lock();
sp<IBinder> object(
mContexts.indexOfKey(name) >= ? mContexts.valueFor(name) : NULL);
mLock.unlock(); //printf("Getting context object %s for %p\n", String8(name).string(), caller.get()); if (object != NULL) return object; // Don't attempt to retrieve contexts if we manage them
if (mManagesContexts) {
LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
String8(name).string());
return NULL;
} IPCThreadState* ipc = IPCThreadState::self();
{
Parcel data, reply;
// no interface token on this magic transaction
data.writeString16(name);
data.writeStrongBinder(caller);
status_t result = ipc->transact( /**magic*/, , data, &reply, );
if (result == NO_ERROR) {
object = reply.readStrongBinder();
}
} ipc->flushCommands(); if (object != NULL) setContextObject(object, name);
return object;
} void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
} bool ProcessState::isContextManager(void) const
{
return mManagesContexts;
} bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
{
if (!mManagesContexts) {
AutoMutex _l(mLock);
mBinderContextCheckFunc = checkFunc;
mBinderContextUserData = userData; int dummy = ;
status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
if (result == ) {
mManagesContexts = true;
} else if (result == -) {
mBinderContextCheckFunc = NULL;
mBinderContextUserData = NULL;
LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
}
}
return mManagesContexts;
} ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = NULL;
e.refs = NULL;
status_t err = mHandleToObject.insertAt(e, N, handle+-N);
if (err < NO_ERROR) return NULL;
}
return &mHandleToObject.editItemAt(handle);
} sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
} return result;
} wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
{
wp<IBinder> result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. The
// attemptIncWeak() is safe because we know the BpBinder destructor will always
// call expungeHandle(), which acquires the same lock we are holding now.
// We need to do this because there is a race condition between someone
// releasing a reference on this BpBinder, and a new reference on its handle
// arriving from the driver.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = new BpBinder(handle);
result = b;
e->binder = b;
if (b) e->refs = b->getWeakRefs();
} else {
result = b;
e->refs->decWeak(this);
}
} return result;
} void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
{
AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); // This handle may have already been replaced with a new BpBinder
// (if someone failed the AttemptIncWeak() above); we don't want
// to overwrite it.
if (e && e->binder == binder) e->binder = NULL;
} void ProcessState::setArgs(int argc, const char* const argv[])
{
mArgC = argc;
mArgV = (const char **)argv; mArgLen = ;
for (int i=; i<argc; i++) {
mArgLen += strlen(argv[i]) + ;
}
mArgLen--;
} int ProcessState::getArgC() const
{
return mArgC;
} const char* const* ProcessState::getArgV() const
{
return mArgV;
} void ProcessState::setArgV0(const char* txt)
{
if (mArgV != NULL) {
strncpy((char*)mArgV[], txt, mArgLen);
set_process_name(txt);
}
} void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
int32_t s = android_atomic_add(, &mThreadPoolSeq);
char buf[];
sprintf(buf, "Binder Thread #%d", s);
LOGV("Spawning new pooled thread, name=%s\n", buf);
sp<Thread> t = new PoolThread(isMain);
t->run(buf);
}
} static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);
if (fd >= ) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -) {
LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -;
}
if (result != || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
LOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -;
}
size_t maxThreads = ;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -) {
LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
} ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq()
{
if (mDriverFD >= ) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, );
if (mVMStart == MAP_FAILED) {
// *sigh*
LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -;
}
#else
mDriverFD = -;
#endif
} LOG_ALWAYS_FATAL_IF(mDriverFD < , "Binder driver could not be opened. Terminating.");
} ProcessState::~ProcessState()
{
} }; // namespace androidProcessState.cpp
- Create a new object of ProcessState and assign to global sp<ProcessState> gProcess;
sp<ProcessState> ProcessState::self()
{
if (gProcess != NULL)
return gProcess;
AutoMutex _l(gProcessMutex);
if (gProcess == NULL)
gProcess = new ProcessState;
return gProcess;
}- Open the binder to get handler of binder
static int open_driver()//every process where the service run or client run will have its own default binder's handle
{
int fd = open("/dev/binder", O_RDWR);
if (fd >= ) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -) {
LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -;
}
if (result != || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
LOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -;
}
size_t maxThreads = ;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -) {
LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
}ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq()
{
if (mDriverFD >= ) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, );
if (mVMStart == MAP_FAILED) {
// *sigh*
LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -;
}
#else
mDriverFD = -;
#endif
}
}PrecessState's Constructor
- PoolThread of ProcessState
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()//override threadLoop of Thread
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};- Start thread pool
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
int32_t s = android_atomic_add(, &mThreadPoolSeq);
char buf[];
sprintf(buf, "Binder Thread #%d", s);
LOGV("Spawning new pooled thread, name=%s\n", buf);
sp<Thread> t = new PoolThread(isMain);
t->run(buf);//thread run by calling threadLoop} }
IPCThreadState
- IPCThreadState.h
/**
* Copyright (C) 2005 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 ANDROID_IPC_THREAD_STATE_H
#define ANDROID_IPC_THREAD_STATE_H #include <utils/Errors.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <utils/Vector.h> #ifdef HAVE_WIN32_PROC
typedef int uid_t;
#endif // ---------------------------------------------------------------------------
namespace android { class IPCThreadState
{
public:
static IPCThreadState* self();
static IPCThreadState* selfOrNull(); // self(), but won't instantiate
sp<ProcessState> process();
status_t clearLastError();
int getCallingPid();
int getCallingUid();
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
void setLastTransactionBinderFlags(int32_t flags);
int32_t getLastTransactionBinderFlags() const;
int64_t clearCallingIdentity();
void restoreCallingIdentity(int64_t token);
void flushCommands();
void joinThreadPool(bool isMain = true);
void stopProcess(bool immediate = true);
status_t transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
void incStrongHandle(int32_t handle);
void decStrongHandle(int32_t handle);
void incWeakHandle(int32_t handle);
void decWeakHandle(int32_t handle);
status_t attemptIncStrongHandle(int32_t handle);
static void expungeHandle(int32_t handle, IBinder* binder);
status_t requestDeathNotification(int32_t handle,
BpBinder* proxy);
status_t clearDeathNotification(int32_t handle,
BpBinder* proxy);
static void shutdown();
static void disableBackgroundScheduling(bool disable);
private:
IPCThreadState();
~IPCThreadState();
status_t sendReply(const Parcel& reply, uint32_t flags);
status_t waitForResponse(Parcel *reply,
status_t *acquireResult=NULL);
status_t talkWithDriver(bool doReceive=true);
status_t writeTransactionData(int32_t cmd,
uint32_t binderFlags,
int32_t handle,
uint32_t code,
const Parcel& data,
status_t* statusBuffer);
status_t executeCommand(int32_t command);
void clearCaller();
static void threadDestructor(void *st);
static void freeBuffer(Parcel* parcel,
const uint8_t* data, size_t dataSize,
const size_t* objects, size_t objectsSize,
void* cookie);
const sp<ProcessState> mProcess;
const pid_t mMyThreadId;
Vector<BBinder*> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs; Parcel mIn;
Parcel mOut;
status_t mLastError;
pid_t mCallingPid;
uid_t mCallingUid;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
};
};
#endif // ANDROID_IPC_THREAD_STATE_HIPCThreadState.h
- IPCThreadState.cpp
/**
* Copyright (C) 2005 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.
*/ #define LOG_TAG "IPCThreadState" #include <binder/IPCThreadState.h> #include <binder/Binder.h>
#include <binder/BpBinder.h>
#include <cutils/sched_policy.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/TextOutput.h>
#include <utils/threads.h> #include <private/binder/binder_module.h>
#include <private/binder/Static.h> #include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h> #ifdef HAVE_PTHREADS
#include <pthread.h>
#include <sched.h>
#include <sys/resource.h>
#endif
#ifdef HAVE_WIN32_THREADS
#include <windows.h>
#endif #if LOG_NDEBUG #define IF_LOG_TRANSACTIONS() if (false)
#define IF_LOG_COMMANDS() if (false)
#define LOG_REMOTEREFS(...)
#define IF_LOG_REMOTEREFS() if (false)
#define LOG_THREADPOOL(...)
#define LOG_ONEWAY(...) #else #define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__) #endif // --------------------------------------------------------------------------- namespace android { static const char* getReturnString(size_t idx);
static const char* getCommandString(size_t idx);
static const void* printReturnCommand(TextOutput& out, const void* _cmd);
static const void* printCommand(TextOutput& out, const void* _cmd); // This will result in a missing symbol failure if the IF_LOG_COMMANDS()
// conditionals don't get stripped... but that is probably what we want.
#if !LOG_NDEBUG
static const char *kReturnStrings[] = {
"BR_ERROR",
"BR_OK",
"BR_TRANSACTION",
"BR_REPLY",
"BR_ACQUIRE_RESULT",
"BR_DEAD_REPLY",
"BR_TRANSACTION_COMPLETE",
"BR_INCREFS",
"BR_ACQUIRE",
"BR_RELEASE",
"BR_DECREFS",
"BR_ATTEMPT_ACQUIRE",
"BR_NOOP",
"BR_SPAWN_LOOPER",
"BR_FINISHED",
"BR_DEAD_BINDER",
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
"BR_FAILED_REPLY"
}; static const char *kCommandStrings[] = {
"BC_TRANSACTION",
"BC_REPLY",
"BC_ACQUIRE_RESULT",
"BC_FREE_BUFFER",
"BC_INCREFS",
"BC_ACQUIRE",
"BC_RELEASE",
"BC_DECREFS",
"BC_INCREFS_DONE",
"BC_ACQUIRE_DONE",
"BC_ATTEMPT_ACQUIRE",
"BC_REGISTER_LOOPER",
"BC_ENTER_LOOPER",
"BC_EXIT_LOOPER",
"BC_REQUEST_DEATH_NOTIFICATION",
"BC_CLEAR_DEATH_NOTIFICATION",
"BC_DEAD_BINDER_DONE"
}; static const char* getReturnString(size_t idx)
{
if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[]))
return kReturnStrings[idx];
else
return "unknown";
} static const char* getCommandString(size_t idx)
{
if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[]))
return kCommandStrings[idx];
else
return "unknown";
} static const void* printBinderTransactionData(TextOutput& out, const void* data)
{
const binder_transaction_data* btd =
(const binder_transaction_data*)data;
if (btd->target.handle < ) {
/** want to print descriptors in decimal; guess based on value */
out << "target.desc=" << btd->target.handle;
} else {
out << "target.ptr=" << btd->target.ptr;
}
out << " (cookie " << btd->cookie << ")" << endl
<< "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
<< "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
<< " bytes)" << endl
<< "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
<< " bytes)";
return btd+;
} static const void* printReturnCommand(TextOutput& out, const void* _cmd)
{
static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[]);
const int32_t* cmd = (const int32_t*)_cmd;
int32_t code = *cmd++;
size_t cmdIndex = code & 0xff;
if (code == (int32_t) BR_ERROR) {
out << "BR_ERROR: " << (void*)(*cmd++) << endl;
return cmd;
} else if (cmdIndex >= N) {
out << "Unknown reply: " << code << endl;
return cmd;
}
out << kReturnStrings[cmdIndex]; switch (code) {
case BR_TRANSACTION:
case BR_REPLY: {
out << ": " << indent;
cmd = (const int32_t *)printBinderTransactionData(out, cmd);
out << dedent;
} break; case BR_ACQUIRE_RESULT: {
const int32_t res = *cmd++;
out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
} break; case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS: {
const int32_t b = *cmd++;
const int32_t c = *cmd++;
out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
} break; case BR_ATTEMPT_ACQUIRE: {
const int32_t p = *cmd++;
const int32_t b = *cmd++;
const int32_t c = *cmd++;
out << ": target=" << (void*)b << " (cookie " << (void*)c
<< "), pri=" << p;
} break; case BR_DEAD_BINDER:
case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
const int32_t c = *cmd++;
out << ": death cookie " << (void*)c;
} break; default:
// no details to show for: BR_OK, BR_DEAD_REPLY,
// BR_TRANSACTION_COMPLETE, BR_FINISHED
break;
} out << endl;
return cmd;
} static const void* printCommand(TextOutput& out, const void* _cmd)
{
static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[]);
const int32_t* cmd = (const int32_t*)_cmd;
int32_t code = *cmd++;
size_t cmdIndex = code & 0xff; if (cmdIndex >= N) {
out << "Unknown command: " << code << endl;
return cmd;
}
out << kCommandStrings[cmdIndex]; switch (code) {
case BC_TRANSACTION:
case BC_REPLY: {
out << ": " << indent;
cmd = (const int32_t *)printBinderTransactionData(out, cmd);
out << dedent;
} break; case BC_ACQUIRE_RESULT: {
const int32_t res = *cmd++;
out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
} break; case BC_FREE_BUFFER: {
const int32_t buf = *cmd++;
out << ": buffer=" << (void*)buf;
} break; case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS: {
const int32_t d = *cmd++;
out << ": desc=" << d;
} break; case BC_INCREFS_DONE:
case BC_ACQUIRE_DONE: {
const int32_t b = *cmd++;
const int32_t c = *cmd++;
out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
} break; case BC_ATTEMPT_ACQUIRE: {
const int32_t p = *cmd++;
const int32_t d = *cmd++;
out << ": desc=" << d << ", pri=" << p;
} break; case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
const int32_t h = *cmd++;
const int32_t c = *cmd++;
out << ": handle=" << h << " (death cookie " << (void*)c << ")";
} break; case BC_DEAD_BINDER_DONE: {
const int32_t c = *cmd++;
out << ": death cookie " << (void*)c;
} break; default:
// no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
// BC_EXIT_LOOPER
break;
} out << endl;
return cmd;
}
#endif static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = ;
static bool gShutdown = false;
static bool gDisableBackgroundScheduling = false; IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS) {
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
}
if (gShutdown) return NULL;
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) {
if (pthread_key_create(&gTLS, threadDestructor) != ) {
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
} IPCThreadState* IPCThreadState::selfOrNull()
{
if (gHaveTLS) {
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
return st;
}
return NULL;
} void IPCThreadState::shutdown()
{
gShutdown = true; if (gHaveTLS) {
// XXX Need to wait for all thread pool threads to exit!
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
if (st) {
delete st;
pthread_setspecific(gTLS, NULL);
}
gHaveTLS = false;
}
} void IPCThreadState::disableBackgroundScheduling(bool disable)
{
gDisableBackgroundScheduling = disable;
} sp<ProcessState> IPCThreadState::process()
{
return mProcess;
} status_t IPCThreadState::clearLastError()
{
const status_t err = mLastError;
mLastError = NO_ERROR;
return err;
} int IPCThreadState::getCallingPid()
{
return mCallingPid;
} int IPCThreadState::getCallingUid()
{
return mCallingUid;
} int64_t IPCThreadState::clearCallingIdentity()
{
int64_t token = ((int64_t)mCallingUid<<) | mCallingPid;
clearCaller();
return token;
} void IPCThreadState::setStrictModePolicy(int32_t policy)
{
mStrictModePolicy = policy;
} int32_t IPCThreadState::getStrictModePolicy() const
{
return mStrictModePolicy;
} void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
{
mLastTransactionBinderFlags = flags;
} int32_t IPCThreadState::getLastTransactionBinderFlags() const
{
return mLastTransactionBinderFlags;
} void IPCThreadState::restoreCallingIdentity(int64_t token)
{
mCallingUid = (int)(token>>);
mCallingPid = (int)token;
} void IPCThreadState::clearCaller()
{
mCallingPid = getpid();
mCallingUid = getuid();
} void IPCThreadState::flushCommands()
{
if (mProcess->mDriverFD <= )
return;
talkWithDriver(false);
} void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
// This thread may have been spawned by a thread that was in the background
// scheduling group, so first we will make sure it is in the default/foreground
// one to avoid performing an initial transaction in the background.
androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
status_t result;
do {
int32_t cmd;
// When we've cleared the incoming command queue, process any pending derefs
if (mIn.dataPosition() >= mIn.dataSize()) {
size_t numPending = mPendingWeakDerefs.size();
if (numPending > ) {
for (size_t i = ; i < numPending; i++) {
RefBase::weakref_type* refs = mPendingWeakDerefs[i];
refs->decWeak(mProcess.get());
}
mPendingWeakDerefs.clear();
}
numPending = mPendingStrongDerefs.size();
if (numPending > ) {
for (size_t i = ; i < numPending; i++) {
BBinder* obj = mPendingStrongDerefs[i];
obj->decStrong(mProcess.get());
}
mPendingStrongDerefs.clear();
}
}
// now get the next command to be processed, waiting if necessary
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) continue;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
result = executeCommand(cmd);
}
// After executing the command, ensure that the thread is returned to the
// default cgroup before rejoining the pool. The driver takes care of
// restoring the priority, but doesn't do anything with cgroups so we
// need to take care of that here in userspace. Note that we do make
// sure to go in the foreground after executing a transaction, but
// there are other callbacks into user code that could have changed
// our group so we want to make absolutely sure it is put back.
androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF); LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
(void*)pthread_self(), getpid(), (void*)result);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
} void IPCThreadState::stopProcess(bool immediate)
{
//LOGI("**** STOPPING PROCESS");
flushCommands();
int fd = mProcess->mDriverFD;
mProcess->mDriverFD = -;
close(fd);
//kill(getpid(), SIGKILL);
} status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck(); flags |= TF_ACCEPT_FDS; IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
} if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == ? "READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
} if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
} if ((flags & TF_ONE_WAY) == ) {
#if 0
if (code == ) { // relayout
LOGI(">>>>>> CALLING transaction 4");
} else {
LOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == ) { // relayout
LOGI("<<<<<< RETURNING transaction 4");
} else {
LOGI("<<<<<< RETURNING transaction %d", code);
}
#endif IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
} return err;
} void IPCThreadState::incStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_ACQUIRE);
mOut.writeInt32(handle);
} void IPCThreadState::decStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_RELEASE);
mOut.writeInt32(handle);
} void IPCThreadState::incWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_INCREFS);
mOut.writeInt32(handle);
} void IPCThreadState::decWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_DECREFS);
mOut.writeInt32(handle);
} status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::attemptIncStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
mOut.writeInt32(); // xxx was thread priority
mOut.writeInt32(handle);
status_t result = UNKNOWN_ERROR; waitForResponse(NULL, &result); #if LOG_REFCOUNTS
printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
#endif return result;
} void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
{
#if LOG_REFCOUNTS
printf("IPCThreadState::expungeHandle(%ld)\n", handle);
#endif
self()->mProcess->expungeHandle(handle, binder);
} status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writeInt32((int32_t)proxy);
return NO_ERROR;
} status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writeInt32((int32_t)proxy);
return NO_ERROR;
} IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mMyThreadId(androidGetTid()),
mStrictModePolicy(),
mLastTransactionBinderFlags()
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity();
mOut.setDataCapacity();
} IPCThreadState::~IPCThreadState()
{
} status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
status_t err;
status_t statusBuffer;
err = writeTransactionData(BC_REPLY, flags, -, , reply, &statusBuffer);
if (err < NO_ERROR) return err; return waitForResponse(NULL, NULL);
} status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err; while () {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == ) continue; cmd = mIn.readInt32(); IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
} switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break; case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish; case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish; case BR_ACQUIRE_RESULT:
{
LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish; case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish; if (reply) {
if ((tr.flags & TF_STATUS_CODE) == ) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t),
freeBuffer, this);
} else {
err = *static_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), this);
}
} else {
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), this);
continue;
}
}
goto finish; default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
} finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
} return err;
} status_t IPCThreadState::talkWithDriver(bool doReceive)
{
LOG_ASSERT(mProcess->mDriverFD >= , "Binder driver is not opened"); binder_write_read bwr; // Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize(); // We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : ; bwr.write_size = outAvail;
bwr.write_buffer = (long unsigned int)mOut.data(); // This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (long unsigned int)mIn.data();
} else {
bwr.read_size = ;
} IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != ) {
alog << "Sending commands to driver: " << indent;
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds)+bwr.write_size;
alog << HexDump(cmds, bwr.write_size) << endl;
while (cmds < end) cmds = printCommand(alog, cmds);
alog << dedent;
}
alog << "Size of receive buffer: " << bwr.read_size
<< ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
} // Return immediately if there is nothing to do.
if ((bwr.write_size == ) && (bwr.read_size == )) return NO_ERROR; bwr.write_consumed = ;
bwr.read_consumed = ;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(HAVE_ANDROID_OS)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= )
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR); IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
} if (err >= NO_ERROR) {
if (bwr.write_consumed > ) {
if (bwr.write_consumed < (ssize_t)mOut.dataSize())
mOut.remove(, bwr.write_consumed);
else
mOut.setDataSize();
}
if (bwr.read_consumed > ) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition();
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
} return err;
} status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr; tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = ;
tr.sender_pid = ;
tr.sender_euid = ; const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = statusBuffer;
tr.offsets_size = ;
tr.data.ptr.offsets = NULL;
} else {
return (mLastError = err);
} mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr)); return NO_ERROR;
} sp<BBinder> the_context_object; void setTheContextObject(sp<BBinder> obj)
{
the_context_object = obj;
} status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR; switch (cmd) {
case BR_ERROR:
result = mIn.readInt32();
break; case BR_OK:
break; case BR_ACQUIRE:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
LOG_ASSERT(refs->refBase() == obj,
"BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
refs, obj, refs->refBase());
obj->incStrong(mProcess.get());
IF_LOG_REMOTEREFS() {
LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
obj->printRefs();
}
mOut.writeInt32(BC_ACQUIRE_DONE);
mOut.writeInt32((int32_t)refs);
mOut.writeInt32((int32_t)obj);
break; case BR_RELEASE:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
LOG_ASSERT(refs->refBase() == obj,
"BR_RELEASE: object %p does not match cookie %p (expected %p)",
refs, obj, refs->refBase());
IF_LOG_REMOTEREFS() {
LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
obj->printRefs();
}
mPendingStrongDerefs.push(obj);
break; case BR_INCREFS:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
refs->incWeak(mProcess.get());
mOut.writeInt32(BC_INCREFS_DONE);
mOut.writeInt32((int32_t)refs);
mOut.writeInt32((int32_t)obj);
break; case BR_DECREFS:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
// NOTE: This assertion is not valid, because the object may no
// longer exist (thus the (BBinder*)cast above resulting in a different
// memory address).
//LOG_ASSERT(refs->refBase() == obj,
// "BR_DECREFS: object %p does not match cookie %p (expected %p)",
// refs, obj, refs->refBase());
mPendingWeakDerefs.push(refs);
break; case BR_ATTEMPT_ACQUIRE:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32(); {
const bool success = refs->attemptIncStrong(mProcess.get());
LOG_ASSERT(success && refs->refBase() == obj,
"BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
refs, obj, refs->refBase()); mOut.writeInt32(BC_ACQUIRE_RESULT);
mOut.writeInt32((int32_t)success);
}
break; case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
LOG_ASSERT(result == NO_ERROR,
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break; Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), freeBuffer, this); const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid; mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid; int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
if (curPrio > ANDROID_PRIORITY_NORMAL) {
// We have inherited a reduced priority from the caller, but do not
// want to run in that state in this process. The driver set our
// priority already (though not our scheduling class), so bounce
// it back to the default before invoking the transaction.
setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
}
} else {
if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
// We want to use the inherited priority from the caller.
// Ensure this thread is in the background scheduling class,
// since the driver won't modify scheduling classes for us.
// The scheduling group is reset to default by the caller
// once this method returns after the transaction is complete.
androidSetThreadSchedulingGroup(mMyThreadId,
ANDROID_TGROUP_BG_NONINTERACT);
}
} //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); Parcel reply;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_TRANSACTION thr " << (void*)pthread_self()
<< " / obj " << tr.target.ptr << " / code "
<< TypeCode(tr.code) << ": " << indent << buffer
<< dedent << endl
<< "Data addr = "
<< reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
<< ", offsets addr="
<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
}
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error); } else {
const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
} //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
// mCallingPid, origPid, origUid); if ((tr.flags & TF_ONE_WAY) == ) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
sendReply(reply, );
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
} mCallingPid = origPid;
mCallingUid = origUid; IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
<< tr.target.ptr << ": " << indent << reply << dedent << endl;
} }
break; case BR_DEAD_BINDER:
{
BpBinder *proxy = (BpBinder*)mIn.readInt32();
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writeInt32((int32_t)proxy);
} break; case BR_CLEAR_DEATH_NOTIFICATION_DONE:
{
BpBinder *proxy = (BpBinder*)mIn.readInt32();
proxy->getWeakRefs()->decWeak(proxy);
} break; case BR_FINISHED:
result = TIMED_OUT;
break; case BR_NOOP:
break; case BR_SPAWN_LOOPER:
mProcess->spawnPooledThread(false);
break; default:
printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
result = UNKNOWN_ERROR;
break;
} if (result != NO_ERROR) {
mLastError = result;
} return result;
} void IPCThreadState::threadDestructor(void *st)
{
IPCThreadState* const self = static_cast<IPCThreadState*>(st);
if (self) {
self->flushCommands();
#if defined(HAVE_ANDROID_OS)
ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, );
#endif
delete self;
}
} void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
const size_t* objects, size_t objectsSize,
void* cookie)
{
//LOGI("Freeing parcel %p", &parcel);
IF_LOG_COMMANDS() {
alog << "Writing BC_FREE_BUFFER for " << data << endl;
}
LOG_ASSERT(data != NULL, "Called with NULL data");
if (parcel != NULL) parcel->closeFileDescriptors();
IPCThreadState* state = self();
state->mOut.writeInt32(BC_FREE_BUFFER);
state->mOut.writeInt32((int32_t)data);
} }; // namespace androidIPCThreadState.cpp
IPCThread.Self()
static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = ;
static bool gShutdown = false;
static bool gDisableBackgroundScheduling = false;
IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS) {
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
}
if (gShutdown) return NULL;
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) {
if (pthread_key_create(&gTLS, threadDestructor) != ) {
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mMyThreadId(androidGetTid()),
mStrictModePolicy(),
mLastTransactionBinderFlags()
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity();
mOut.setDataCapacity();
}- joinThreadPool
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
status_t result;
do {
int32_t cmd;
if (mIn.dataPosition() >= mIn.dataSize()) {
size_t numPending = mPendingWeakDerefs.size();
if (numPending > ) {
for (size_t i = ; i < numPending; i++) {
RefBase::weakref_type* refs = mPendingWeakDerefs[i];
refs->decWeak(mProcess.get());
}
mPendingWeakDerefs.clear();
}
numPending = mPendingStrongDerefs.size();
if (numPending > ) {
for (size_t i = ; i < numPending; i++) {
BBinder* obj = mPendingStrongDerefs[i];
obj->decStrong(mProcess.get());
}
mPendingStrongDerefs.clear();
}
}
// now get the next command to be processed, waiting if necessary
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) continue;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
result = executeCommand(cmd);
}
androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
(void*)pthread_self(), getpid(), (void*)result);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
Android Process & Thread的更多相关文章
- [Java][Android][Process] 暴力的服务能够解决一切,暴力的方式运行命令行语句
不管是在Java或者Android中运行命令行语句殊途同归都是创建一个子进程运行调用可运行文件运行命令.类似于Windows中的CMD一样. 此时你有两种方式运行:ProcessBuilder与Run ...
- [Java][Android][Process] ProcessBuilder与Runtime差别
在Android中想要进行Ping,在不Root机器的情况下似乎还仅仅能进行底层命调用才干实现. 由于在Java中要进行ICMP包发送须要Root权限. 于是仅仅能通过创建进程来攻克了.创建进程在Ja ...
- Android:关于声明文件中android:process属性说明
笔者在学习Android Service组件的过程中碰到了一个问题,就是在Android应用的声明文件Manifest.xml中有时候会对相关的服务标签设置一个android:process=&quo ...
- Android开发之android:process=":remote"
由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象.在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将 ...
- Android handler Thread 修改UI Demo
/********************************************************************** * Android handler Thread 修改U ...
- android:process为耗资源操作指定一个新进程
当有一些耗费内存比较多的操作时,可以通过android:process指定一个新的进程.保证程序运行. 例如: 一个后台长期运行的service: <service android:name=& ...
- apk,task,android:process与android:sharedUserId的区别
apk一般占一个dalvik,一个进程,一个task.通过设置也可以多个进程,占多个task. task是一个activity的栈,其中"可能"含有来自多个App的activity ...
- android.process.acore和system进程
从源码看来,android.process.acore进程应该是一些基本功能的载入程序. android-4.3_r2.2中,它包括以下项目: 1.UserDictionaryProvider < ...
- Linux中的task,process, thread 简介
本文的主要目的是介绍在Linux内核中,task,process, thread这3个名字之间的区别和联系.并且和WINDOWS中的相应观念进行比较.如果你已经很清楚了,那么就不用往下看了. LINU ...
随机推荐
- 异步解决方案(三)Promise
首先建议大家先看看这篇博文,这是我看过的最清晰给力的博文了: https://www.cnblogs.com/lvdabao/p/es6-promise-1.html 附赠一篇笑死我了的博客,加入有一 ...
- Life is a journey
Life is a journey. What we should care about is not where it's headed but what we see and how we fee ...
- caffe 图片数据的转换成lmdb和数据集均值(转)
转自网站: http://blog.csdn.net/muyiyushan/article/details/70578077 1.准备数据 使用dog/cat数据集,在训练项目根目录下分别建立trai ...
- hdu 6297(常用的输出格式总结)
题目链接:https://cn.vjudge.net/problem/HDU-6297 题目介绍:一道关于输出格式规范问题 wrong answer代码: #include<iostream&g ...
- component: resolve => require(['../pages/home.vue'], resolve)
component: resolve => require(['../pages/home.vue'], resolve) vue 路由的懒加载 import Vue from 'vue' im ...
- Linux IPC 共享内存
共享内存 共享内存(shared memory)是最简单的Linux进程间通信方式之一. 使用共享内存,不同进程可以对同一块内存进行读写. 由于所有进程对共享内存的访问就和访问自己的内存空间一样,而不 ...
- elasticsearch 插件 大全
本文使用的elasticsearch版本:1.7.3 推荐几款比较常用的elasticsearch插件 1.集群监控插件 bigdesk node cluster 2.集群资源查看和查询插件 kopf ...
- Silverlight 用户代码未处理 TypeLoadException
在Silverlight中动态创建Enum时,多次调用改方法出现上图所示错误,后来发现定义名称都是一样的, 在程序中声明全局变量去区别就可以了. int num = 1; private Type C ...
- JAVA HTTP请求和HTTPS请求
HTTP与HTTPS区别:http://blog.csdn.net/lyhjava/article/details/51860215 URL发送 HTTP.HTTPS:http://blog.csdn ...
- springboot 启动的java进程默默终止
首先说明这是一个灵异事件......... 场景1 :把之前用map实现的缓存用Redis重构,高高兴兴上线更新,10 分钟后,老板告诉我,项目停了,what ??? 像我这么帅气,英俊,聪明的人,更 ...