MediaService.Main

 #include <sys/types.h>
#include <unistd.h>
#include <grp.h> #include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h> #include <AudioFlinger.h>
#include <CameraService.h>
#include <MediaPlayerService.h>
#include <AudioPolicyService.h>
#include <private/android_filesystem_config.h> using namespace android; 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();
}
  1.  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();
    }
  • What is sp?   include/utils/StrongPointer.h
  •  #ifndef ANDROID_STRONG_POINTER_H
    #define ANDROID_STRONG_POINTER_H #include <cutils/atomic.h> #include <stdint.h>
    #include <sys/types.h>
    #include <stdlib.h> // ---------------------------------------------------------------------------
    namespace android { class TextOutput;
    TextOutput& printStrongPointer(TextOutput& to, const void* val); template<typename T> class wp; // --------------------------------------------------------------------------- #define COMPARE(_op_) \
    inline bool operator _op_ (const sp<T>& o) const { \
    return m_ptr _op_ o.m_ptr; \
    } \
    inline bool operator _op_ (const T* o) const { \
    return m_ptr _op_ o; \
    } \
    template<typename U> \
    inline bool operator _op_ (const sp<U>& o) const { \
    return m_ptr _op_ o.m_ptr; \
    } \
    template<typename U> \
    inline bool operator _op_ (const U* o) const { \
    return m_ptr _op_ o; \
    } \
    inline bool operator _op_ (const wp<T>& o) const { \
    return m_ptr _op_ o.m_ptr; \
    } \
    template<typename U> \
    inline bool operator _op_ (const wp<U>& o) const { \
    return m_ptr _op_ o.m_ptr; \
    } // --------------------------------------------------------------------------- template <typename T>
    class sp
    {
    public:
    inline sp() : m_ptr() { } sp(T* other);
    sp(const sp<T>& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other); ~sp(); // Assignment sp& operator = (T* other);
    sp& operator = (const sp<T>& other); template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (U* other); //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other); // Reset void clear(); // Accessors inline T& operator* () const { return *m_ptr; }
    inline T* operator-> () const { return m_ptr; }
    inline T* get() const { return m_ptr; } // Operators COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=) private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
    }; #undef COMPARE template <typename T>
    TextOutput& operator<<(TextOutput& to, const sp<T>& val); // ---------------------------------------------------------------------------
    // No user serviceable parts below here. template<typename T>
    sp<T>::sp(T* other)
    : m_ptr(other)
    {
    if (other) other->incStrong(this);
    } template<typename T>
    sp<T>::sp(const sp<T>& other)
    : m_ptr(other.m_ptr)
    {
    if (m_ptr) m_ptr->incStrong(this);
    } template<typename T> template<typename U>
    sp<T>::sp(U* other) : m_ptr(other)
    {
    if (other) ((T*)other)->incStrong(this);
    } template<typename T> template<typename U>
    sp<T>::sp(const sp<U>& other)
    : m_ptr(other.m_ptr)
    {
    if (m_ptr) m_ptr->incStrong(this);
    } template<typename T>
    sp<T>::~sp()
    {
    if (m_ptr) m_ptr->decStrong(this);
    } template<typename T>
    sp<T>& sp<T>::operator = (const sp<T>& other) {
    T* otherPtr(other.m_ptr);
    if (otherPtr) otherPtr->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = otherPtr;
    return *this;
    } template<typename T>
    sp<T>& sp<T>::operator = (T* other)
    {
    if (other) other->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
    } template<typename T> template<typename U>
    sp<T>& sp<T>::operator = (const sp<U>& other)
    {
    T* otherPtr(other.m_ptr);
    if (otherPtr) otherPtr->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = otherPtr;
    return *this;
    } template<typename T> template<typename U>
    sp<T>& sp<T>::operator = (U* other)
    {
    if (other) ((T*)other)->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
    } template<typename T>
    void sp<T>::force_set(T* other)
    {
    other->forceIncStrong(this);
    m_ptr = other;
    } template<typename T>
    void sp<T>::clear()
    {
    if (m_ptr) {
    m_ptr->decStrong(this);
    m_ptr = ;
    }
    } template<typename T>
    void sp<T>::set_pointer(T* ptr) {
    m_ptr = ptr;
    } template <typename T>
    inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
    {
    return printStrongPointer(to, val.get());
    } }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_STRONG_POINTER_H

    sp

     template <typename T>
    class sp
    {
    public:
    inline sp() : m_ptr() { }
    sp(T* other);
    sp(const sp<T>& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);
    ~sp();
    // Assignment
    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);
    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (U* other);
    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);
    // Reset
    void clear();
    // Accessors
    inline T& operator* () const { return *m_ptr; }
    inline T* operator-> () const { return m_ptr; }
    inline T* get() const { return m_ptr; }
    // Operators
    private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
    };
  • What is ProcessState? libs/binder/ProcessState.cpp,include/binder/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.
    */ #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 android

    ProcessState

    sp<ProcessState> ProcessState::self()
    {
    if (gProcess != NULL)
    return gProcess;
    AutoMutex _l(gProcessMutex);
    if (gProcess == NULL)
    gProcess = new ProcessState;
    return gProcess;
    }
     #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();//Singleton
    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;
    };
     /**
    * 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 "RefBase" #include <utils/RefBase.h> #include <utils/Atomic.h>
    #include <utils/CallStack.h>
    #include <utils/Log.h>
    #include <utils/threads.h>
    #include <utils/TextOutput.h> #include <stdlib.h>
    #include <stdio.h>
    #include <typeinfo>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h> // compile with refcounting debugging enabled
    #define DEBUG_REFS 0
    #define DEBUG_REFS_FATAL_SANITY_CHECKS 0
    #define DEBUG_REFS_ENABLED_BY_DEFAULT 1
    #define DEBUG_REFS_CALLSTACK_ENABLED 1 // log all reference counting operations
    #define PRINT_REFS 0 // --------------------------------------------------------------------------- namespace android { #define INITIAL_STRONG_VALUE (1<<28) // --------------------------------------------------------------------------- class RefBase::weakref_impl : public RefBase::weakref_type
    {
    public:
    volatile int32_t mStrong;
    volatile int32_t mWeak;
    RefBase* const mBase;
    volatile int32_t mFlags; #if !DEBUG_REFS weakref_impl(RefBase* base)
    : mStrong(INITIAL_STRONG_VALUE)
    , mWeak()
    , mBase(base)
    , mFlags()
    {
    } void addStrongRef(const void* /**id*/) { }
    void removeStrongRef(const void* /**id*/) { }
    void renameStrongRefId(const void* /**old_id*/, const void* /**new_id*/) { }
    void addWeakRef(const void* /**id*/) { }
    void removeWeakRef(const void* /**id*/) { }
    void renameWeakRefId(const void* /**old_id*/, const void* /**new_id*/) { }
    void printRefs() const { }
    void trackMe(bool, bool) { } #else weakref_impl(RefBase* base)
    : mStrong(INITIAL_STRONG_VALUE)
    , mWeak()
    , mBase(base)
    , mFlags()
    , mStrongRefs(NULL)
    , mWeakRefs(NULL)
    , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
    , mRetain(false)
    {
    } ~weakref_impl()
    {
    bool dumpStack = false;
    if (!mRetain && mStrongRefs != NULL) {
    dumpStack = true;
    #if DEBUG_REFS_FATAL_SANITY_CHECKS
    LOG_ALWAYS_FATAL("Strong references remain!");
    #else
    LOGE("Strong references remain:");
    #endif
    ref_entry* refs = mStrongRefs;
    while (refs) {
    char inc = refs->ref >= ? '+' : '-';
    LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
    #if DEBUG_REFS_CALLSTACK_ENABLED
    refs->stack.dump();
    #endif
    refs = refs->next;
    }
    } if (!mRetain && mWeakRefs != NULL) {
    dumpStack = true;
    #if DEBUG_REFS_FATAL_SANITY_CHECKS
    LOG_ALWAYS_FATAL("Weak references remain:");
    #else
    LOGE("Weak references remain!");
    #endif
    ref_entry* refs = mWeakRefs;
    while (refs) {
    char inc = refs->ref >= ? '+' : '-';
    LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
    #if DEBUG_REFS_CALLSTACK_ENABLED
    refs->stack.dump();
    #endif
    refs = refs->next;
    }
    }
    if (dumpStack) {
    LOGE("above errors at:");
    CallStack stack;
    stack.update();
    stack.dump();
    }
    } void addStrongRef(const void* id) {
    //LOGD_IF(mTrackEnabled,
    // "addStrongRef: RefBase=%p, id=%p", mBase, id);
    addRef(&mStrongRefs, id, mStrong);
    } void removeStrongRef(const void* id) {
    //LOGD_IF(mTrackEnabled,
    // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
    if (!mRetain) {
    removeRef(&mStrongRefs, id);
    } else {
    addRef(&mStrongRefs, id, -mStrong);
    }
    } void renameStrongRefId(const void* old_id, const void* new_id) {
    //LOGD_IF(mTrackEnabled,
    // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
    // mBase, old_id, new_id);
    renameRefsId(mStrongRefs, old_id, new_id);
    } void addWeakRef(const void* id) {
    addRef(&mWeakRefs, id, mWeak);
    } void removeWeakRef(const void* id) {
    if (!mRetain) {
    removeRef(&mWeakRefs, id);
    } else {
    addRef(&mWeakRefs, id, -mWeak);
    }
    } void renameWeakRefId(const void* old_id, const void* new_id) {
    renameRefsId(mWeakRefs, old_id, new_id);
    } void trackMe(bool track, bool retain)
    {
    mTrackEnabled = track;
    mRetain = retain;
    } void printRefs() const
    {
    String8 text; {
    Mutex::Autolock _l(mMutex);
    char buf[];
    sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
    text.append(buf);
    printRefsLocked(&text, mStrongRefs);
    sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
    text.append(buf);
    printRefsLocked(&text, mWeakRefs);
    } {
    char name[];
    snprintf(name, , "/data/%p.stack", this);
    int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
    if (rc >= ) {
    write(rc, text.string(), text.length());
    close(rc);
    LOGD("STACK TRACE for %p saved in %s", this, name);
    }
    else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
    name, strerror(errno));
    }
    } private:
    struct ref_entry
    {
    ref_entry* next;
    const void* id;
    #if DEBUG_REFS_CALLSTACK_ENABLED
    CallStack stack;
    #endif
    int32_t ref;
    }; void addRef(ref_entry** refs, const void* id, int32_t mRef)
    {
    if (mTrackEnabled) {
    AutoMutex _l(mMutex); ref_entry* ref = new ref_entry;
    // Reference count at the time of the snapshot, but before the
    // update. Positive value means we increment, negative--we
    // decrement the reference count.
    ref->ref = mRef;
    ref->id = id;
    #if DEBUG_REFS_CALLSTACK_ENABLED
    ref->stack.update();
    #endif
    ref->next = *refs;
    *refs = ref;
    }
    } void removeRef(ref_entry** refs, const void* id)
    {
    if (mTrackEnabled) {
    AutoMutex _l(mMutex); ref_entry* const head = *refs;
    ref_entry* ref = head;
    while (ref != NULL) {
    if (ref->id == id) {
    *refs = ref->next;
    delete ref;
    return;
    }
    refs = &ref->next;
    ref = *refs;
    } #if DEBUG_REFS_FATAL_SANITY_CHECKS
    LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
    "(weakref_type %p) that doesn't exist!",
    id, mBase, this);
    #endif LOGE("RefBase: removing id %p on RefBase %p"
    "(weakref_type %p) that doesn't exist!",
    id, mBase, this); ref = head;
    while (ref) {
    char inc = ref->ref >= ? '+' : '-';
    LOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
    ref = ref->next;
    } CallStack stack;
    stack.update();
    stack.dump();
    }
    } void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
    {
    if (mTrackEnabled) {
    AutoMutex _l(mMutex);
    ref_entry* ref = r;
    while (ref != NULL) {
    if (ref->id == old_id) {
    ref->id = new_id;
    }
    ref = ref->next;
    }
    }
    } void printRefsLocked(String8* out, const ref_entry* refs) const
    {
    char buf[];
    while (refs) {
    char inc = refs->ref >= ? '+' : '-';
    sprintf(buf, "\t%c ID %p (ref %d):\n",
    inc, refs->id, refs->ref);
    out->append(buf);
    #if DEBUG_REFS_CALLSTACK_ENABLED
    out->append(refs->stack.toString("\t\t"));
    #else
    out->append("\t\t(call stacks disabled)");
    #endif
    refs = refs->next;
    }
    } mutable Mutex mMutex;
    ref_entry* mStrongRefs;
    ref_entry* mWeakRefs; bool mTrackEnabled;
    // Collect stack traces on addref and removeref, instead of deleting the stack references
    // on removeref that match the address ones.
    bool mRetain; #endif
    }; // --------------------------------------------------------------------------- void RefBase::incStrong(const void* id) const
    {
    weakref_impl* const refs = mRefs;
    refs->incWeak(id); refs->addStrongRef(id);
    const int32_t c = android_atomic_inc(&refs->mStrong);
    LOG_ASSERT(c > , "incStrong() called on %p after last strong ref", refs);
    #if PRINT_REFS
    LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
    #endif
    if (c != INITIAL_STRONG_VALUE) {
    return;
    } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    refs->mBase->onFirstRef();
    } void RefBase::decStrong(const void* id) const
    {
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    const int32_t c = android_atomic_dec(&refs->mStrong);
    #if PRINT_REFS
    LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
    #endif
    LOG_ASSERT(c >= , "decStrong() called on %p too many times", refs);
    if (c == ) {
    refs->mBase->onLastStrongRef(id);
    if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
    delete this;
    }
    }
    refs->decWeak(id);
    } void RefBase::forceIncStrong(const void* id) const
    {
    weakref_impl* const refs = mRefs;
    refs->incWeak(id); refs->addStrongRef(id);
    const int32_t c = android_atomic_inc(&refs->mStrong);
    LOG_ASSERT(c >= , "forceIncStrong called on %p after ref count underflow",
    refs);
    #if PRINT_REFS
    LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
    #endif switch (c) {
    case INITIAL_STRONG_VALUE:
    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    // fall through...
    case :
    refs->mBase->onFirstRef();
    }
    } int32_t RefBase::getStrongCount() const
    {
    return mRefs->mStrong;
    } RefBase* RefBase::weakref_type::refBase() const
    {
    return static_cast<const weakref_impl*>(this)->mBase;
    } void RefBase::weakref_type::incWeak(const void* id)
    {
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c = android_atomic_inc(&impl->mWeak);
    LOG_ASSERT(c >= , "incWeak called on %p after last weak ref", this);
    } void RefBase::weakref_type::decWeak(const void* id)
    {
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    const int32_t c = android_atomic_dec(&impl->mWeak);
    LOG_ASSERT(c >= , "decWeak called on %p too many times", this);
    if (c != ) return; if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
    // This is the regular lifetime case. The object is destroyed
    // when the last strong reference goes away. Since weakref_impl
    // outlive the object, it is not destroyed in the dtor, and
    // we'll have to do it here.
    if (impl->mStrong == INITIAL_STRONG_VALUE) {
    // Special case: we never had a strong reference, so we need to
    // destroy the object now.
    delete impl->mBase;
    } else {
    // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
    delete impl;
    }
    } else {
    // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
    impl->mBase->onLastWeakRef(id);
    if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
    // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
    // is gone, we can destroy the object.
    delete impl->mBase;
    }
    }
    } bool RefBase::weakref_type::attemptIncStrong(const void* id)
    {
    incWeak(id); weakref_impl* const impl = static_cast<weakref_impl*>(this); int32_t curCount = impl->mStrong;
    LOG_ASSERT(curCount >= , "attemptIncStrong called on %p after underflow",
    this);
    while (curCount > && curCount != INITIAL_STRONG_VALUE) {
    if (android_atomic_cmpxchg(curCount, curCount+, &impl->mStrong) == ) {
    break;
    }
    curCount = impl->mStrong;
    } if (curCount <= || curCount == INITIAL_STRONG_VALUE) {
    bool allow;
    if (curCount == INITIAL_STRONG_VALUE) {
    // Attempting to acquire first strong reference... this is allowed
    // if the object does NOT have a longer lifetime (meaning the
    // implementation doesn't need to see this), or if the implementation
    // allows it to happen.
    allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
    || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
    } else {
    // Attempting to revive the object... this is allowed
    // if the object DOES have a longer lifetime (so we can safely
    // call the object with only a weak ref) and the implementation
    // allows it to happen.
    allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
    && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
    }
    if (!allow) {
    decWeak(id);
    return false;
    }
    curCount = android_atomic_inc(&impl->mStrong); // If the strong reference count has already been incremented by
    // someone else, the implementor of onIncStrongAttempted() is holding
    // an unneeded reference. So call onLastStrongRef() here to remove it.
    // (No, this is not pretty.) Note that we MUST NOT do this if we
    // are in fact acquiring the first reference.
    if (curCount > && curCount < INITIAL_STRONG_VALUE) {
    impl->mBase->onLastStrongRef(id);
    }
    } impl->addStrongRef(id); #if PRINT_REFS
    LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
    #endif if (curCount == INITIAL_STRONG_VALUE) {
    android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
    impl->mBase->onFirstRef();
    } return true;
    } bool RefBase::weakref_type::attemptIncWeak(const void* id)
    {
    weakref_impl* const impl = static_cast<weakref_impl*>(this); int32_t curCount = impl->mWeak;
    LOG_ASSERT(curCount >= , "attemptIncWeak called on %p after underflow",
    this);
    while (curCount > ) {
    if (android_atomic_cmpxchg(curCount, curCount+, &impl->mWeak) == ) {
    break;
    }
    curCount = impl->mWeak;
    } if (curCount > ) {
    impl->addWeakRef(id);
    } return curCount > ;
    } int32_t RefBase::weakref_type::getWeakCount() const
    {
    return static_cast<const weakref_impl*>(this)->mWeak;
    } void RefBase::weakref_type::printRefs() const
    {
    static_cast<const weakref_impl*>(this)->printRefs();
    } void RefBase::weakref_type::trackMe(bool enable, bool retain)
    {
    static_cast<weakref_impl*>(this)->trackMe(enable, retain);
    } RefBase::weakref_type* RefBase::createWeak(const void* id) const
    {
    mRefs->incWeak(id);
    return mRefs;
    } RefBase::weakref_type* RefBase::getWeakRefs() const
    {
    return mRefs;
    } RefBase::RefBase()
    : mRefs(new weakref_impl(this))
    {
    } RefBase::~RefBase()
    {
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
    // we never acquired a strong (and/or weak) reference on this object.
    delete mRefs;
    } else {
    // life-time of this object is extended to WEAK or FOREVER, in
    // which case weakref_impl doesn't out-live the object and we
    // can free it now.
    if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
    // It's possible that the weak count is not 0 if the object
    // re-acquired a weak reference in its destructor
    if (mRefs->mWeak == ) {
    delete mRefs;
    }
    }
    }
    // for debugging purposes, clear this.
    const_cast<weakref_impl*&>(mRefs) = NULL;
    } void RefBase::extendObjectLifetime(int32_t mode)
    {
    android_atomic_or(mode, &mRefs->mFlags);
    } void RefBase::onFirstRef()
    {
    } void RefBase::onLastStrongRef(const void* /**id*/)
    {
    } bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
    {
    return (flags&FIRST_INC_STRONG) ? true : false;
    } void RefBase::onLastWeakRef(const void* /**id*/)
    {
    } // --------------------------------------------------------------------------- void RefBase::moveReferences(void* dst, void const* src, size_t n,
    const ReferenceConverterBase& caster)
    {
    #if DEBUG_REFS
    const size_t itemSize = caster.getReferenceTypeSize();
    for (size_t i= ; i<n ; i++) {
    void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize);
    void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
    RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
    ref->mRefs->renameStrongRefId(s, d);
    ref->mRefs->renameWeakRefId(s, d);
    }
    #endif
    } // --------------------------------------------------------------------------- TextOutput& printStrongPointer(TextOutput& to, const void* val)
    {
    to << "sp<>(" << val << ")";
    return to;
    } TextOutput& printWeakPointer(TextOutput& to, const void* val)
    {
    to << "wp<>(" << val << ")";
    return to;
    } }; // namespace android

    RefBase

     /**
    * 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 android

    IPCThreadState

  • What is IServiceManager?
  •  namespace android {
    IInterface::IInterface(): RefBase() {}
    IInterface::~IInterface() {
    }
    sp<IBinder> IInterface::asBinder()
    {
    return this ? onAsBinder() : NULL;
    }
    sp<const IBinder> IInterface::asBinder() const
    {
    return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
    }
    };

    IInterface

  •  namespace android {
    class IServiceManager : public IInterface
    {
    public:
    DECLARE_META_INTERFACE(ServiceManager);
    virtual sp<IBinder> getService( const String16& name) const = ;
    virtual sp<IBinder> checkService( const String16& name) const = ;
    virtual status_t addService( const String16& name,const sp<IBinder>& service) = ;
    virtual Vector<String16> listServices() = ;
    enum {
    GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
    CHECK_SERVICE_TRANSACTION,
    ADD_SERVICE_TRANSACTION,
    LIST_SERVICES_TRANSACTION,
    };
    };
    sp<IServiceManager> defaultServiceManager();
    template<typename INTERFACE>
    status_t getService(const String16& name, sp<INTERFACE>* outService)
    {
    const sp<IServiceManager> sm = defaultServiceManager();
    if (sm != NULL) {
    *outService = interface_cast<INTERFACE>(sm->getService(name));
    if ((*outService) != NULL) return NO_ERROR;
    }
    return NAME_NOT_FOUND;
    }
    bool checkCallingPermission(const String16& permission);
    bool checkCallingPermission(const String16& permission,int32_t* outPid, int32_t* outUid);
    bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
    class BnServiceManager : public BnInterface<IServiceManager>
    {
    public:
    virtual status_t onTransact( uint32_t code,
    const Parcel& data,
    Parcel* reply,
    uint32_t flags = );
    };
    };

    IServiceManager.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.
    */ #define LOG_TAG "ServiceManager" #include <binder/IServiceManager.h> #include <utils/Debug.h>
    #include <utils/Log.h>
    #include <binder/IPCThreadState.h>
    #include <binder/Parcel.h>
    #include <utils/String8.h>
    #include <utils/SystemClock.h> #include <private/binder/Static.h> #include <unistd.h> namespace android { sp<IServiceManager> defaultServiceManager()
    {
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager; {
    AutoMutex _l(gDefaultServiceManagerLock);
    if (gDefaultServiceManager == NULL) {
    gDefaultServiceManager = interface_cast<IServiceManager>(
    ProcessState::self()->getContextObject(NULL));
    }
    } return gDefaultServiceManager;
    } bool checkCallingPermission(const String16& permission)
    {
    return checkCallingPermission(permission, NULL, NULL);
    } static String16 _permission("permission"); bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
    {
    IPCThreadState* ipcState = IPCThreadState::self();
    pid_t pid = ipcState->getCallingPid();
    uid_t uid = ipcState->getCallingUid();
    if (outPid) *outPid = pid;
    if (outUid) *outUid = uid;
    return checkPermission(permission, pid, uid);
    } bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
    {
    sp<IPermissionController> pc;
    gDefaultServiceManagerLock.lock();
    pc = gPermissionController;
    gDefaultServiceManagerLock.unlock(); int64_t startTime = ; while (true) {
    if (pc != NULL) {
    bool res = pc->checkPermission(permission, pid, uid);
    if (res) {
    if (startTime != ) {
    LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
    (int)((uptimeMillis()-startTime)/),
    String8(permission).string(), uid, pid);
    }
    return res;
    } // Is this a permission failure, or did the controller go away?
    if (pc->asBinder()->isBinderAlive()) {
    LOGW("Permission failure: %s from uid=%d pid=%d",
    String8(permission).string(), uid, pid);
    return false;
    } // Object is dead!
    gDefaultServiceManagerLock.lock();
    if (gPermissionController == pc) {
    gPermissionController = NULL;
    }
    gDefaultServiceManagerLock.unlock();
    } // Need to retrieve the permission controller.
    sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
    if (binder == NULL) {
    // Wait for the permission controller to come back...
    if (startTime == ) {
    startTime = uptimeMillis();
    LOGI("Waiting to check permission %s from uid=%d pid=%d",
    String8(permission).string(), uid, pid);
    }
    sleep();
    } else {
    pc = interface_cast<IPermissionController>(binder);
    // Install the new permission controller, and try again.
    gDefaultServiceManagerLock.lock();
    gPermissionController = pc;
    gDefaultServiceManagerLock.unlock();
    }
    }
    } // ---------------------------------------------------------------------- class BpServiceManager : public BpInterface<IServiceManager>
    {
    public:
    BpServiceManager(const sp<IBinder>& impl)
    : BpInterface<IServiceManager>(impl)
    {
    } virtual sp<IBinder> getService(const String16& name) const
    {
    unsigned n;
    for (n = ; n < ; n++){
    sp<IBinder> svc = checkService(name);
    if (svc != NULL) return svc;
    LOGI("Waiting for service %s...\n", String8(name).string());
    sleep();
    }
    return NULL;
    } virtual sp<IBinder> checkService( const String16& name) const
    {
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
    return reply.readStrongBinder();
    } virtual status_t addService(const String16& name, const sp<IBinder>& service)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    data.writeStrongBinder(service);
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
    } virtual Vector<String16> listServices()
    {
    Vector<String16> res;
    int n = ; for (;;) {
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeInt32(n++);
    status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
    if (err != NO_ERROR)
    break;
    res.add(reply.readString16());
    }
    return res;
    }
    }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); // ---------------------------------------------------------------------- status_t BnServiceManager::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
    //printf("ServiceManager received: "); data.print();
    switch(code) {
    case GET_SERVICE_TRANSACTION: {
    CHECK_INTERFACE(IServiceManager, data, reply);
    String16 which = data.readString16();
    sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
    reply->writeStrongBinder(b);
    return NO_ERROR;
    } break;
    case CHECK_SERVICE_TRANSACTION: {
    CHECK_INTERFACE(IServiceManager, data, reply);
    String16 which = data.readString16();
    sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
    reply->writeStrongBinder(b);
    return NO_ERROR;
    } break;
    case ADD_SERVICE_TRANSACTION: {
    CHECK_INTERFACE(IServiceManager, data, reply);
    String16 which = data.readString16();
    sp<IBinder> b = data.readStrongBinder();
    status_t err = addService(which, b);
    reply->writeInt32(err);
    return NO_ERROR;
    } break;
    case LIST_SERVICES_TRANSACTION: {
    CHECK_INTERFACE(IServiceManager, data, reply);
    Vector<String16> list = listServices();
    const size_t N = list.size();
    reply->writeInt32(N);
    for (size_t i=; i<N; i++) {
    reply->writeString16(list[i]);
    }
    return NO_ERROR;
    } break;
    default:
    return BBinder::onTransact(code, data, reply, flags);
    }
    } }; // namespace android

    IServiceManager.cpp

  • What is defaultServiceManager?
  •  1 sp<IServiceManager> defaultServiceManager() //global function
    2 {
    3 if (gDefaultServiceManager != NULL)
    4 return gDefaultServiceManager;
    5 {
    6 AutoMutex _l(gDefaultServiceManagerLock);
    7 if (gDefaultServiceManager == NULL) {
    8 gDefaultServiceManager = interface_cast<IServiceManager>(
    9 ProcessState::self()->getContextObject(NULL));
    10 }
    11 }
    12 return gDefaultServiceManager;
    13 }
    1 sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
    2 {
    3 return getStrongProxyForHandle(0);
    4 }
     1 sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    2 {
    3 sp<IBinder> result;
    4 AutoMutex _l(mLock);
    5 handle_entry* e = lookupHandleLocked(handle)
    6 if (e != NULL) {
    7 IBinder* b = e->binder;
    8 if (b == NULL || !e->refs->attemptIncWeak(this)) {
    9 b = new BpBinder(handle);
    10 e->binder = b;
    11 if (b) e->refs = b->getWeakRefs();
    12 result = b;
    13 } else {
    14 result.force_set(b);
    15 e->refs->decWeak(this);
    16 }
    17 }
    18 return result;
    19 }

AudioFlinger

MediaPlayerService

  • Create service in current process and add it to service manager
  •  void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
    String16("media.player"), new MediaPlayerService());
    }
    //
    MediaPlayerService::MediaPlayerService()
    {
    LOGV("MediaPlayerService created");
    mNextConnId = ; mBatteryAudio.refCount = ;
    for (int i = ; i < NUM_AUDIO_DEVICES; i++) {
    mBatteryAudio.deviceOn[i] = ;
    mBatteryAudio.lastTime[i] = ;
    mBatteryAudio.totalTime[i] = ;
    }
    // speaker is on by default
    mBatteryAudio.deviceOn[SPEAKER] = ;
  • Now we have MediaService information in service manager
  • MediaPlayerService is subclass of BnMediaPlayerService
  •  class MediaPlayerService : public BnMediaPlayerService
  • Where is BnMediaPlayerService
  •  namespace android {
    class IMediaRecorder;
    class IOMX;
    struct IStreamSource;
    class IMediaPlayerService: public IInterface
    {
    public:
    DECLARE_META_INTERFACE(MediaPlayerService);
    virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = ;
    virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = ;
    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId = ) = ; virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = ;
    virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = ;
    virtual sp<IOMX> getOMX() = ;
    ............
    virtual void addBatteryData(uint32_t params) = ;
    virtual status_t pullBatteryData(Parcel* reply) = ;
    };
    class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
    {
    public:
    virtual status_t onTransact( uint32_t code,
    const Parcel& data,
    Parcel* reply,
    uint32_t flags = );
    };
    };
  • What does BnMediaPlayerService do?
  • How to use MediaPlayer
  •  MediaPlayer mp = new MediaPlayer();//new a MediaPlayer object
    mp.setDataSource("/sdcard/test.mp3");//set music path
    mp.prepare();//prepare
    mp.start();//start to play
  • JNI of MediaPlayer

  •  /**
    **
    ** Copyright 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 "MediaPlayer-JNI"
    #include "utils/Log.h" #include <media/mediaplayer.h>
    #include <media/MediaPlayerInterface.h>
    #include <stdio.h>
    #include <assert.h>
    #include <limits.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <utils/threads.h>
    #include "jni.h"
    #include "JNIHelp.h"
    #include "android_runtime/AndroidRuntime.h"
    #include "android_runtime/android_view_Surface.h"
    #include "utils/Errors.h" // for status_t
    #include "utils/KeyedVector.h"
    #include "utils/String8.h"
    #include "android_media_Utils.h" #include "android_util_Binder.h"
    #include <binder/Parcel.h>
    #include <gui/ISurfaceTexture.h>
    #include <surfaceflinger/Surface.h>
    #include <binder/IPCThreadState.h>
    #include <binder/IServiceManager.h> // ---------------------------------------------------------------------------- using namespace android; // ---------------------------------------------------------------------------- struct fields_t {
    jfieldID context;
    jfieldID surface_texture; jmethodID post_event;
    };
    static fields_t fields; static Mutex sLock; // ----------------------------------------------------------------------------
    // ref-counted object for callbacks
    class JNIMediaPlayerListener: public MediaPlayerListener
    {
    public:
    JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
    ~JNIMediaPlayerListener();
    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
    private:
    JNIMediaPlayerListener();
    jclass mClass; // Reference to MediaPlayer class
    jobject mObject; // Weak ref to MediaPlayer Java object to call on
    }; JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
    { // Hold onto the MediaPlayer class for use in calling the static method
    // that posts events to the application thread.
    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
    LOGE("Can't find android/media/MediaPlayer");
    jniThrowException(env, "java/lang/Exception", NULL);
    return;
    }
    mClass = (jclass)env->NewGlobalRef(clazz); // We use a weak reference so the MediaPlayer object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    mObject = env->NewGlobalRef(weak_thiz);
    } JNIMediaPlayerListener::~JNIMediaPlayerListener()
    {
    // remove global references
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    env->DeleteGlobalRef(mObject);
    env->DeleteGlobalRef(mClass);
    } void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
    {
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (obj && obj->dataSize() > ) {
    jbyteArray jArray = env->NewByteArray(obj->dataSize());
    if (jArray != NULL) {
    jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
    memcpy(nArray, obj->data(), obj->dataSize());
    env->ReleaseByteArrayElements(jArray, nArray, );
    env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
    msg, ext1, ext2, jArray);
    env->DeleteLocalRef(jArray);
    }
    } else {
    env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
    msg, ext1, ext2, NULL);
    }
    } // ---------------------------------------------------------------------------- static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
    {
    Mutex::Autolock l(sLock);
    MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
    return sp<MediaPlayer>(p);
    } static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
    {
    Mutex::Autolock l(sLock);
    sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
    if (player.get()) {
    player->incStrong(thiz);
    }
    if (old != ) {
    old->decStrong(thiz);
    }
    env->SetIntField(thiz, fields.context, (int)player.get());
    return old;
    } // If exception is NULL and opStatus is not OK, this method sends an error
    // event to the client application; otherwise, if exception is not NULL and
    // opStatus is not OK, this method throws the given exception to the client
    // application.
    static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
    {
    if (exception == NULL) { // Don't throw exception. Instead, send an event.
    if (opStatus != (status_t) OK) {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp != ) mp->notify(MEDIA_ERROR, opStatus, );
    }
    } else { // Throw exception!
    if ( opStatus == (status_t) INVALID_OPERATION ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
    jniThrowException(env, "java/lang/SecurityException", NULL);
    } else if ( opStatus != (status_t) OK ) {
    if (strlen(message) > ) {
    // if the message is too long, don't bother displaying the status code
    jniThrowException( env, exception, message);
    } else {
    char msg[];
    // append the status code to the message
    sprintf(msg, "%s: status=0x%X", message, opStatus);
    jniThrowException( env, exception, msg);
    }
    }
    }
    } static void
    android_media_MediaPlayer_setDataSourceAndHeaders(
    JNIEnv *env, jobject thiz, jstring path,
    jobjectArray keys, jobjectArray values) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    } if (path == NULL) {
    jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    return;
    } const char *tmp = env->GetStringUTFChars(path, NULL);
    if (tmp == NULL) { // Out of memory
    return;
    }
    LOGV("setDataSource: path %s", tmp); String8 pathStr(tmp);
    env->ReleaseStringUTFChars(path, tmp);
    tmp = NULL; // We build a KeyedVector out of the key and val arrays
    KeyedVector<String8, String8> headersVector;
    if (!ConvertKeyValueArraysToKeyedVector(
    env, keys, values, &headersVector)) {
    return;
    } status_t opStatus =
    mp->setDataSource(
    pathStr,
    headersVector.size() > ? &headersVector : NULL); process_media_player_call(
    env, thiz, opStatus, "java/io/IOException",
    "setDataSource failed." );
    } static void
    android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
    {
    android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL, NULL);
    } static void
    android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    } if (fileDescriptor == NULL) {
    jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    return;
    }
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    LOGV("setDataSourceFD: fd %d", fd);
    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
    } static sp<ISurfaceTexture>
    getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
    ISurfaceTexture * const p = (ISurfaceTexture*)env->GetIntField(thiz, fields.surface_texture);
    return sp<ISurfaceTexture>(p);
    } static void
    decVideoSurfaceRef(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL) {
    return;
    } sp<ISurfaceTexture> old_st = getVideoSurfaceTexture(env, thiz);
    if (old_st != NULL) {
    old_st->decStrong(thiz);
    }
    } static void
    setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL) {
    if (mediaPlayerMustBeAlive) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    }
    return;
    } decVideoSurfaceRef(env, thiz); sp<ISurfaceTexture> new_st;
    if (jsurface) {
    sp<Surface> surface(Surface_getSurface(env, jsurface));
    if (surface != NULL) {
    new_st = surface->getSurfaceTexture();
    new_st->incStrong(thiz);
    } else {
    jniThrowException(env, "java/lang/IllegalArgumentException",
    "The surface has been released");
    return;
    }
    } env->SetIntField(thiz, fields.surface_texture, (int)new_st.get()); // This will fail if the media player has not been initialized yet. This
    // can be the case if setDisplay() on MediaPlayer.java has been called
    // before setDataSource(). The redundant call to setVideoSurfaceTexture()
    // in prepare/prepareAsync covers for this case.
    mp->setVideoSurfaceTexture(new_st);
    } static void
    android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
    {
    setVideoSurface(env, thiz, jsurface, true /** mediaPlayerMustBeAlive */);
    } static void
    android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    } // Handle the case where the display surface was set before the mp was
    // initialized. We try again to make it stick.
    sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz);
    mp->setVideoSurfaceTexture(st); process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
    } static void
    android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    } // Handle the case where the display surface was set before the mp was
    // initialized. We try again to make it stick.
    sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz);
    mp->setVideoSurfaceTexture(st); process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
    } static void
    android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
    {
    LOGV("start");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
    } static void
    android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
    {
    LOGV("stop");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
    } static void
    android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
    {
    LOGV("pause");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
    } static jboolean
    android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return false;
    }
    const jboolean is_playing = mp->isPlaying(); LOGV("isPlaying: %d", is_playing);
    return is_playing;
    } static void
    android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    LOGV("seekTo: %d(msec)", msec);
    process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
    } static int
    android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return ;
    }
    int w;
    if ( != mp->getVideoWidth(&w)) {
    LOGE("getVideoWidth failed");
    w = ;
    }
    LOGV("getVideoWidth: %d", w);
    return w;
    } static int
    android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return ;
    }
    int h;
    if ( != mp->getVideoHeight(&h)) {
    LOGE("getVideoHeight failed");
    h = ;
    }
    LOGV("getVideoHeight: %d", h);
    return h;
    } static int
    android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return ;
    }
    int msec;
    process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
    LOGV("getCurrentPosition: %d (msec)", msec);
    return msec;
    } static int
    android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return ;
    }
    int msec;
    process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
    LOGV("getDuration: %d (msec)", msec);
    return msec;
    } static void
    android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
    {
    LOGV("reset");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
    } static void
    android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype)
    {
    LOGV("setAudioStreamType: %d", streamtype);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL );
    } static void
    android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
    {
    LOGV("setLooping: %d", looping);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
    } static jboolean
    android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
    {
    LOGV("isLooping");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return false;
    }
    return mp->isLooping();
    } static void
    android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume)
    {
    LOGV("setVolume: left %f right %f", leftVolume, rightVolume);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL );
    } // FIXME: deprecated
    static jobject
    android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec)
    {
    return NULL;
    } // Sends the request and reply parcels to the media player via the
    // binder interface.
    static jint
    android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
    jobject java_request, jobject java_reply)
    {
    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
    if (media_player == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return UNKNOWN_ERROR;
    } Parcel *request = parcelForJavaObject(env, java_request);
    Parcel *reply = parcelForJavaObject(env, java_reply); // Don't use process_media_player_call which use the async loop to
    // report errors, instead returns the status.
    return media_player->invoke(*request, reply);
    } // Sends the new filter to the client.
    static jint
    android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
    {
    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
    if (media_player == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return UNKNOWN_ERROR;
    } Parcel *filter = parcelForJavaObject(env, request); if (filter == NULL ) {
    jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
    return UNKNOWN_ERROR;
    } return media_player->setMetadataFilter(*filter);
    } static jboolean
    android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
    jboolean apply_filter, jobject reply)
    {
    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
    if (media_player == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return false;
    } Parcel *metadata = parcelForJavaObject(env, reply); if (metadata == NULL ) {
    jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
    return false;
    } metadata->freeData();
    // On return metadata is positioned at the beginning of the
    // metadata. Note however that the parcel actually starts with the
    // return code so you should not rewind the parcel using
    // setDataPosition(0).
    return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
    } // This function gets some field IDs, which in turn causes class initialization.
    // It is called from a static block in MediaPlayer, which won't run until the
    // first time an instance of this class is used.
    static void
    android_media_MediaPlayer_native_init(JNIEnv *env)
    {
    jclass clazz; clazz = env->FindClass("android/media/MediaPlayer");
    if (clazz == NULL) {
    return;
    } fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
    if (fields.context == NULL) {
    return;
    } fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
    "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    if (fields.post_event == NULL) {
    return;
    } fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I");
    if (fields.surface_texture == NULL) {
    return;
    }
    } static void
    android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
    {
    LOGV("native_setup");
    sp<MediaPlayer> mp = new MediaPlayer();
    if (mp == NULL) {
    jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
    return;
    } // create new listener and give it to MediaPlayer
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener); // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    setMediaPlayer(env, thiz, mp);
    } static void
    android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
    {
    LOGV("release");
    decVideoSurfaceRef(env, thiz);
    sp<MediaPlayer> mp = setMediaPlayer(env, thiz, );
    if (mp != NULL) {
    // this prevents native callbacks after the object is released
    mp->setListener();
    mp->disconnect();
    }
    } static void
    android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
    {
    LOGV("native_finalize");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp != NULL) {
    LOGW("MediaPlayer finalized without being released");
    }
    android_media_MediaPlayer_release(env, thiz);
    } static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) {
    LOGV("set_session_id(): %d", sessionId);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );
    } static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) {
    LOGV("get_session_id()");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return ;
    } return mp->getAudioSessionId();
    } static void
    android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
    {
    LOGV("setAuxEffectSendLevel: level %f", level);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
    } static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) {
    LOGV("attachAuxEffect(): %d", effectId);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
    } static jint
    android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply)
    {
    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
    if (service.get() == NULL) {
    jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
    return UNKNOWN_ERROR;
    } Parcel *reply = parcelForJavaObject(env, java_reply); return service->pullBatteryData(reply);
    } static jboolean
    android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
    {
    LOGV("setParameter: key %d", key);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return false;
    } Parcel *request = parcelForJavaObject(env, java_request);
    status_t err = mp->setParameter(key, *request);
    if (err == OK) {
    return true;
    } else {
    return false;
    }
    } static void
    android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply)
    {
    LOGV("getParameter: key %d", key);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    } Parcel *reply = parcelForJavaObject(env, java_reply);
    process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL );
    } // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = {
    {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource}, {
    "_setDataSource",
    "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
    (void *)android_media_MediaPlayer_setDataSourceAndHeaders
    }, {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
    {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
    {"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
    {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
    {"_start", "()V", (void *)android_media_MediaPlayer_start},
    {"_stop", "()V", (void *)android_media_MediaPlayer_stop},
    {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
    {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
    {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
    {"_pause", "()V", (void *)android_media_MediaPlayer_pause},
    {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
    {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
    {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
    {"_release", "()V", (void *)android_media_MediaPlayer_release},
    {"_reset", "()V", (void *)android_media_MediaPlayer_reset},
    {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
    {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
    {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
    {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
    {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
    {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
    {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
    {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
    {"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
    {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
    {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
    {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
    {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
    {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
    {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
    {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
    {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter},
    {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter},
    }; static const char* const kClassPathName = "android/media/MediaPlayer"; // This function only registers the native methods
    static int register_android_media_MediaPlayer(JNIEnv *env)
    {
    return AndroidRuntime::registerNativeMethods(env,
    "android/media/MediaPlayer", gMethods, NELEM(gMethods));
    } extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
    extern int register_android_media_MediaRecorder(JNIEnv *env);
    extern int register_android_media_MediaScanner(JNIEnv *env);
    extern int register_android_media_ResampleInputStream(JNIEnv *env);
    extern int register_android_media_MediaProfiles(JNIEnv *env);
    extern int register_android_media_AmrInputStream(JNIEnv *env);
    extern int register_android_mtp_MtpDatabase(JNIEnv *env);
    extern int register_android_mtp_MtpDevice(JNIEnv *env);
    extern int register_android_mtp_MtpServer(JNIEnv *env); jint JNI_OnLoad(JavaVM* vm, void* reserved)
    {
    JNIEnv* env = NULL;
    jint result = -; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    LOGE("ERROR: GetEnv failed\n");
    goto bail;
    }
    assert(env != NULL); if (register_android_media_MediaPlayer(env) < ) {
    LOGE("ERROR: MediaPlayer native registration failed\n");
    goto bail;
    } if (register_android_media_MediaRecorder(env) < ) {
    LOGE("ERROR: MediaRecorder native registration failed\n");
    goto bail;
    } if (register_android_media_MediaScanner(env) < ) {
    LOGE("ERROR: MediaScanner native registration failed\n");
    goto bail;
    } if (register_android_media_MediaMetadataRetriever(env) < ) {
    LOGE("ERROR: MediaMetadataRetriever native registration failed\n");
    goto bail;
    } if (register_android_media_AmrInputStream(env) < ) {
    LOGE("ERROR: AmrInputStream native registration failed\n");
    goto bail;
    } if (register_android_media_ResampleInputStream(env) < ) {
    LOGE("ERROR: ResampleInputStream native registration failed\n");
    goto bail;
    } if (register_android_media_MediaProfiles(env) < ) {
    LOGE("ERROR: MediaProfiles native registration failed");
    goto bail;
    } if (register_android_mtp_MtpDatabase(env) < ) {
    LOGE("ERROR: MtpDatabase native registration failed");
    goto bail;
    } if (register_android_mtp_MtpDevice(env) < ) {
    LOGE("ERROR: MtpDevice native registration failed");
    goto bail;
    } if (register_android_mtp_MtpServer(env) < ) {
    LOGE("ERROR: MtpServer native registration failed");
    goto bail;
    } /** success -- return valid version number */
    result = JNI_VERSION_1_4; bail:
    return result;
    } // KTHXBYE
  • what happend when new a MediaPlayer
  •  static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
    {
    LOGV("native_setup");
    sp<MediaPlayer> mp = new MediaPlayer();
    if (mp == NULL) {
    jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
    return;
    }
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);
    setMediaPlayer(env, thiz, mp);
    }
  •  static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
    {
    Mutex::Autolock l(sLock);
    sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
    if (player.get()) {
    player->incStrong(thiz);
    }
    if (old != ) {
    old->decStrong(thiz);
    }
    env->SetIntField(thiz, fields.context, (int)player.get());
    return old;
    }
  •  static void
    android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    if (fileDescriptor == NULL) {
    jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    return;
    }
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    LOGV("setDataSourceFD: fd %d", fd);
    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
    }
  •  status_t MediaPlayer::setDataSource(
    const char *url, const KeyedVector<String8, String8> *headers)
    {
    LOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
    const sp<IMediaPlayerService>& service(getMediaPlayerService());//now we got a mediaPlayerService
    if (service != ) {
    sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
    if (NO_ERROR != player->setDataSource(url, headers)) {
    player.clear();
    }
    err = attachNewPlayer(player);
    }
    }
    return err;
    }
  •  const sp<IMediaPlayerService>& IMediaDeathNotifier::getMediaPlayerService()
    {
    LOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService.get() == ) {
    sp<IServiceManager> sm = defaultServiceManager(); //get media player serice from service manager
    sp<IBinder> binder;
    do {
    binder = sm->getService(String16("media.player"));
    if (binder != ) {
    break;
    }
    LOGW("Media player service not published, waiting...");
    usleep(); // 0.5 s
    } while(true); if (sDeathNotifier == NULL) {
    sDeathNotifier = new DeathNotifier();
    }
    binder->linkToDeath(sDeathNotifier);
    sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);Now we have BpMediaPlayer object
    }
    LOGE_IF(sMediaPlayerService == , "no media player service!?");
    return sMediaPlayerService;
    }
  • what happend when prepare
  •  static void android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
    {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz);
    mp->setVideoSurfaceTexture(st);
    process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
    }
  • start on media player
  •  static void android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
    {
    LOGV("start");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return;
    }
    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
    }
  • process of command send to mediaPlayer
  •  static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
    {
    if (exception == NULL) { // Don't throw exception. Instead, send an event.
    if (opStatus != (status_t) OK) {
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp != ) mp->notify(MEDIA_ERROR, opStatus, );
    }
    } else { // Throw exception!
    if ( opStatus == (status_t) INVALID_OPERATION ) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
    jniThrowException(env, "java/lang/SecurityException", NULL);
    } else if ( opStatus != (status_t) OK ) {
    if (strlen(message) > ) {
    jniThrowException( env, exception, message);
    } else {
    char msg[];
    sprintf(msg, "%s: status=0x%X", message, opStatus);
    jniThrowException( env, exception, msg);
    }
    }
    }
    }
  • How to get media player
  •  static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
    {
    Mutex::Autolock l(sLock);
    MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
    return sp<MediaPlayer>(p);
    }
  • The methods in MediaPlayer.cpp
  •  status_t MediaPlayer::start()
    {
    LOGV("start");
    Mutex::Autolock _l(mLock);
    if (mCurrentState & MEDIA_PLAYER_STARTED)
    return NO_ERROR;
    if ( (mPlayer != ) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
    mPlayer->setLooping(mLoop);
    mPlayer->setVolume(mLeftVolume, mRightVolume);
    mPlayer->setAuxEffectSendLevel(mSendLevel);
    mCurrentState = MEDIA_PLAYER_STARTED;
    status_t ret = mPlayer->start(); //now call BpMediaPlayer.start()
    if (ret != NO_ERROR) {
    mCurrentState = MEDIA_PLAYER_STATE_ERROR;
    } else {
    if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
    LOGV("playback completed immediately following start()");
    }
    }
    return ret;
    }
    LOGE("start called in state %d", mCurrentState);
    return INVALID_OPERATION;
    }
  • BpMediaPlayer
  •  /**
    **
    ** Copyright 2008, The Android Open Source Project
    **
    ** Licensed under the Apache License, Version 2.0 (the "License");
    ** you may not use this file except in compliance with the License.
    ** You may obtain a copy of the License at
    **
    ** http://www.apache.org/licenses/LICENSE-2.0
    **
    ** Unless required by applicable law or agreed to in writing, software
    ** distributed under the License is distributed on an "AS IS" BASIS,
    ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    ** See the License for the specific language governing permissions and
    ** limitations under the License.
    */ #include <stdint.h>
    #include <sys/types.h> #include <binder/Parcel.h> #include <media/IMediaPlayer.h>
    #include <media/IStreamSource.h> #include <surfaceflinger/ISurface.h>
    #include <surfaceflinger/Surface.h>
    #include <gui/ISurfaceTexture.h>
    #include <utils/String8.h> namespace android { enum {
    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
    SET_DATA_SOURCE_URL,
    SET_DATA_SOURCE_FD,
    SET_DATA_SOURCE_STREAM,
    SET_VIDEO_SURFACE,
    PREPARE_ASYNC,
    START,
    STOP,
    IS_PLAYING,
    PAUSE,
    SEEK_TO,
    GET_CURRENT_POSITION,
    GET_DURATION,
    RESET,
    SET_AUDIO_STREAM_TYPE,
    SET_LOOPING,
    SET_VOLUME,
    INVOKE,
    SET_METADATA_FILTER,
    GET_METADATA,
    SET_AUX_EFFECT_SEND_LEVEL,
    ATTACH_AUX_EFFECT,
    SET_VIDEO_SURFACETEXTURE,
    SET_PARAMETER,
    GET_PARAMETER,
    }; class BpMediaPlayer: public BpInterface<IMediaPlayer>
    {
    public:
    BpMediaPlayer(const sp<IBinder>& impl)
    : BpInterface<IMediaPlayer>(impl)
    {
    } // disconnect from media player service
    void disconnect()
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(DISCONNECT, data, &reply);
    } status_t setDataSource(const char* url,
    const KeyedVector<String8, String8>* headers)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeCString(url);
    if (headers == NULL) {
    data.writeInt32();
    } else {
    // serialize the headers
    data.writeInt32(headers->size());
    for (size_t i = ; i < headers->size(); ++i) {
    data.writeString8(headers->keyAt(i));
    data.writeString8(headers->valueAt(i));
    }
    }
    remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
    return reply.readInt32();
    } status_t setDataSource(int fd, int64_t offset, int64_t length) {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeFileDescriptor(fd);
    data.writeInt64(offset);
    data.writeInt64(length);
    remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
    return reply.readInt32();
    } status_t setDataSource(const sp<IStreamSource> &source) {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeStrongBinder(source->asBinder());
    remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply);
    return reply.readInt32();
    } // pass the buffered Surface to the media player service
    status_t setVideoSurface(const sp<Surface>& surface)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    Surface::writeToParcel(surface, &data);
    remote()->transact(SET_VIDEO_SURFACE, data, &reply);
    return reply.readInt32();
    } // pass the buffered ISurfaceTexture to the media player service
    status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    sp<IBinder> b(surfaceTexture->asBinder());
    data.writeStrongBinder(b);
    remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply);
    return reply.readInt32();
    } status_t prepareAsync()
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(PREPARE_ASYNC, data, &reply);
    return reply.readInt32();
    } status_t start()
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(START, data, &reply);
    return reply.readInt32();
    } status_t stop()
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(STOP, data, &reply);
    return reply.readInt32();
    } status_t isPlaying(bool* state)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(IS_PLAYING, data, &reply);
    *state = reply.readInt32();
    return reply.readInt32();
    } status_t pause()
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(PAUSE, data, &reply);
    return reply.readInt32();
    } status_t seekTo(int msec)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeInt32(msec);
    remote()->transact(SEEK_TO, data, &reply);
    return reply.readInt32();
    } status_t getCurrentPosition(int* msec)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(GET_CURRENT_POSITION, data, &reply);
    *msec = reply.readInt32();
    return reply.readInt32();
    } status_t getDuration(int* msec)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(GET_DURATION, data, &reply);
    *msec = reply.readInt32();
    return reply.readInt32();
    } status_t reset()
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(RESET, data, &reply);
    return reply.readInt32();
    } status_t setAudioStreamType(int type)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeInt32(type);
    remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
    return reply.readInt32();
    } status_t setLooping(int loop)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeInt32(loop);
    remote()->transact(SET_LOOPING, data, &reply);
    return reply.readInt32();
    } status_t setVolume(float leftVolume, float rightVolume)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeFloat(leftVolume);
    data.writeFloat(rightVolume);
    remote()->transact(SET_VOLUME, data, &reply);
    return reply.readInt32();
    } status_t invoke(const Parcel& request, Parcel *reply)
    {
    // Avoid doing any extra copy. The interface descriptor should
    // have been set by MediaPlayer.java.
    return remote()->transact(INVOKE, request, reply);
    } status_t setMetadataFilter(const Parcel& request)
    {
    Parcel reply;
    // Avoid doing any extra copy of the request. The interface
    // descriptor should have been set by MediaPlayer.java.
    remote()->transact(SET_METADATA_FILTER, request, &reply);
    return reply.readInt32();
    } status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
    {
    Parcel request;
    request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
    request.writeInt32(update_only);
    request.writeInt32(apply_filter);
    remote()->transact(GET_METADATA, request, reply);
    return reply->readInt32();
    } status_t setAuxEffectSendLevel(float level)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeFloat(level);
    remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply);
    return reply.readInt32();
    } status_t attachAuxEffect(int effectId)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeInt32(effectId);
    remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
    return reply.readInt32();
    } status_t setParameter(int key, const Parcel& request)
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeInt32(key);
    if (request.dataSize() > ) {
    data.appendFrom(const_cast<Parcel *>(&request), , request.dataSize());
    }
    remote()->transact(SET_PARAMETER, data, &reply);
    return reply.readInt32();
    } status_t getParameter(int key, Parcel *reply)
    {
    Parcel data;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    data.writeInt32(key);
    return remote()->transact(GET_PARAMETER, data, reply);
    } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); // ---------------------------------------------------------------------- status_t BnMediaPlayer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
    switch(code) {
    case DISCONNECT: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    disconnect();
    return NO_ERROR;
    } break;
    case SET_DATA_SOURCE_URL: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    const char* url = data.readCString();
    KeyedVector<String8, String8> headers;
    int32_t numHeaders = data.readInt32();
    for (int i = ; i < numHeaders; ++i) {
    String8 key = data.readString8();
    String8 value = data.readString8();
    headers.add(key, value);
    }
    reply->writeInt32(setDataSource(url, numHeaders > ? &headers : NULL));
    return NO_ERROR;
    } break;
    case SET_DATA_SOURCE_FD: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    int fd = data.readFileDescriptor();
    int64_t offset = data.readInt64();
    int64_t length = data.readInt64();
    reply->writeInt32(setDataSource(fd, offset, length));
    return NO_ERROR;
    }
    case SET_DATA_SOURCE_STREAM: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    sp<IStreamSource> source =
    interface_cast<IStreamSource>(data.readStrongBinder());
    reply->writeInt32(setDataSource(source));
    return NO_ERROR;
    }
    case SET_VIDEO_SURFACE: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    sp<Surface> surface = Surface::readFromParcel(data);
    reply->writeInt32(setVideoSurface(surface));
    return NO_ERROR;
    } break;
    case SET_VIDEO_SURFACETEXTURE: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    sp<ISurfaceTexture> surfaceTexture =
    interface_cast<ISurfaceTexture>(data.readStrongBinder());
    reply->writeInt32(setVideoSurfaceTexture(surfaceTexture));
    return NO_ERROR;
    } break;
    case PREPARE_ASYNC: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(prepareAsync());
    return NO_ERROR;
    } break;
    case START: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(start());
    return NO_ERROR;
    } break;
    case STOP: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(stop());
    return NO_ERROR;
    } break;
    case IS_PLAYING: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    bool state;
    status_t ret = isPlaying(&state);
    reply->writeInt32(state);
    reply->writeInt32(ret);
    return NO_ERROR;
    } break;
    case PAUSE: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(pause());
    return NO_ERROR;
    } break;
    case SEEK_TO: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(seekTo(data.readInt32()));
    return NO_ERROR;
    } break;
    case GET_CURRENT_POSITION: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    int msec;
    status_t ret = getCurrentPosition(&msec);
    reply->writeInt32(msec);
    reply->writeInt32(ret);
    return NO_ERROR;
    } break;
    case GET_DURATION: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    int msec;
    status_t ret = getDuration(&msec);
    reply->writeInt32(msec);
    reply->writeInt32(ret);
    return NO_ERROR;
    } break;
    case RESET: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(reset());
    return NO_ERROR;
    } break;
    case SET_AUDIO_STREAM_TYPE: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(setAudioStreamType(data.readInt32()));
    return NO_ERROR;
    } break;
    case SET_LOOPING: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(setLooping(data.readInt32()));
    return NO_ERROR;
    } break;
    case SET_VOLUME: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    float leftVolume = data.readFloat();
    float rightVolume = data.readFloat();
    reply->writeInt32(setVolume(leftVolume, rightVolume));
    return NO_ERROR;
    } break;
    case INVOKE: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    status_t result = invoke(data, reply);
    return result;
    } break;
    case SET_METADATA_FILTER: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(setMetadataFilter(data));
    return NO_ERROR;
    } break;
    case GET_METADATA: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    bool update_only = static_cast<bool>(data.readInt32());
    bool apply_filter = static_cast<bool>(data.readInt32());
    const status_t retcode = getMetadata(update_only, apply_filter, reply);
    reply->setDataPosition();
    reply->writeInt32(retcode);
    reply->setDataPosition();
    return NO_ERROR;
    } break;
    case SET_AUX_EFFECT_SEND_LEVEL: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(setAuxEffectSendLevel(data.readFloat()));
    return NO_ERROR;
    } break;
    case ATTACH_AUX_EFFECT: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    reply->writeInt32(attachAuxEffect(data.readInt32()));
    return NO_ERROR;
    } break;
    case SET_PARAMETER: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    int key = data.readInt32(); Parcel request;
    if (data.dataAvail() > ) {
    request.appendFrom(
    const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
    }
    request.setDataPosition();
    reply->writeInt32(setParameter(key, request));
    return NO_ERROR;
    } break;
    case GET_PARAMETER: {
    CHECK_INTERFACE(IMediaPlayer, data, reply);
    return getParameter(data.readInt32(), reply);
    } break;
    default:
    return BBinder::onTransact(code, data, reply, flags);
    }
    } // ---------------------------------------------------------------------------- }; // namespace android

    BpMediaPlayer

     status_t BpMediaPlayer::stop()
    {
    Parcel data, reply;
    data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
    remote()->transact(STOP, data, &reply);
    return reply.readInt32();
    }
     class BpMediaPlayer: public BpInterface<IMediaPlayer>
    {
    public:
    BpMediaPlayer(const sp<IBinder>& impl)
    : BpInterface<IMediaPlayer>(impl)
    {
    }
    .........................
    }
    template<INTERFACE>
    class BpInterface : public INTERFACE, public BpRefBase
    {
    public:
    BpInterface(const sp<IBinder>& remote);
    protected:
    virtual IBinder* onAsBinder();
    };
  •  Call BpBinder::transact()

           

 status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status =
IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = ;
return status;
}
return DEAD_OBJECT;
}
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);
}
................
}
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;
}

 

CameraService

AudioPolicyService

Reference:http://www.cnblogs.com/eustoma/archive/2011/08/22/2415824.html

http://blog.csdn.net/eustoma/article/details/6706492

http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html

Android's Media的更多相关文章

  1. Android -- com.android.providers.media,external.db

    external.db android是管理多媒体文件(音频.视频.图片)的信息是在/data/data/com.android.providers.media下的数据库文件external.db. ...

  2. java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/images/media/20 from pid=711, uid=10074 requires android.permission.READ_

    java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider ur ...

  3. Android开发 ---Media

    1.ctivity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...

  4. android stream media

    http://www.cnblogs.com/skyseraph/archive/2012/03/31/2427593.html http://www.cnblogs.com/lingyunhu/p/ ...

  5. Android学习笔记——文件路径(/mnt/sdcard/...)、Uri(content://media/external/...)学习

    一.URI 通用资源标志符(Universal Resource Identifier, 简称"URI"). Uri代表要操作的数据,Android上可用的每种资源 - 图像.视频 ...

  6. Android MediaStore与Media.EXTERNAL_CONTENT_URI

    MediaStore这个类是Android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取.这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,andro ...

  7. Android 文件路径(/mnt/sdcard/...)、Uri(content://media/external/...)

    一.URI 通用资源标志符(Universal Resource Identifier, 简称"URI"). Uri代表要操作的数据,Android上可用的每种资源 - 图像.视频 ...

  8. Android Lint Checks

    Android Lint Checks Here are the current list of checks that lint performs as of Android Studio 2.3 ...

  9. Android进程整理

    一.概括 系统启动架构图: 上图在Android系统-开篇中有讲解,是从Android系统启动的角度来分析,本文是从进程/线程的视角来分析该问题. 1.1 父进程 在所有进程中,以父进程的姿态存在的进 ...

随机推荐

  1. 「NOI.AC」Leaves 线段树合并

    题目描述 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有\(n\)个叶子节点,满足这些权值为\(1\dots n\)的一个排列).可以任意交换每个非叶子节点的左右孩子. ...

  2. springboot整合springtask

    在使用 springmvc 中,一般的定时任务是使用 job 或者 quartz 或者timer来实现,但是使用它们的时候比较麻烦,会在 xml 文件中配置很多, springboot 的定时任务比较 ...

  3. linux中tomcat内存溢出

    刚开始测试服务器与线上后台都不能上传10分钟以上的视频,后来只要是视频就不能上传,进入服务器查日志得到如下错误: Caused by: java.lang.OutOfMemoryError: Java ...

  4. STM32F030 定时器多次溢出才触发中断的问题

    前言 最近在调试项目过程中,用了 STM32F030 的定时器 16 作为系统时钟,1ms 触发一次中断,过程中遇到一些值得记录的问题. 记录 STM32F030 中定时器 16 的初始化配置如下 v ...

  5. poj3111 选取物品(二分+贪心)

    题目传送门 题意就是,n个物品,从中选取k个,要按照那个公式所取的值最大. 思路:最大化平均值的时候首先想到的就是二分, 我们设G(x) 为单位的重量不小于X, 我们的目标就是要找到满足条件的最大的X ...

  6. javascript中的一元操作符

    题目如下: var s1 = "01"; var s2 = "1.1"; var s3 = "z"; var b = false; var ...

  7. 2015苏州大学ACM-ICPC集训队选拔赛(1) 1007

    连通图 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Submissio ...

  8. sqlserver 事务日志

    预写式日志(Write-Ahead Logging (WAL)) --在数据写入到数据库之前,先写入到日志. 1.”Begin Tran”记录  -> 缓冲区 2. 日志             ...

  9. UML箭头

    继承(泛化):用实线空心三角箭头表示 实现(接口):用虚线空心三角形箭头标示 依赖:虚线箭头,类A指向类B 方法参数需要传入另一个类的对象,就表示依赖这个类 关联:实线箭头,类A指向类B 一个类的全局 ...

  10. 问题解决Determine IP information for eth0.. no link present check cable

    网上方法都没有解决:简单粗暴编辑里还原了默认设置OK了 网上方法1 一般解决办法: 第一步: 到/etc/sysconfig/network-scripts/ifcfg-eth<n>/et ...