Android's Media
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();
}
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_Hsp
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 androidProcessState
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 androidRefBase
/**
* Copyright (C) 2005 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ #define LOG_TAG "IPCThreadState" #include <binder/IPCThreadState.h> #include <binder/Binder.h>
#include <binder/BpBinder.h>
#include <cutils/sched_policy.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/TextOutput.h>
#include <utils/threads.h> #include <private/binder/binder_module.h>
#include <private/binder/Static.h> #include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h> #ifdef HAVE_PTHREADS
#include <pthread.h>
#include <sched.h>
#include <sys/resource.h>
#endif
#ifdef HAVE_WIN32_THREADS
#include <windows.h>
#endif #if LOG_NDEBUG #define IF_LOG_TRANSACTIONS() if (false)
#define IF_LOG_COMMANDS() if (false)
#define LOG_REMOTEREFS(...)
#define IF_LOG_REMOTEREFS() if (false)
#define LOG_THREADPOOL(...)
#define LOG_ONEWAY(...) #else #define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__) #endif // --------------------------------------------------------------------------- namespace android { static const char* getReturnString(size_t idx);
static const char* getCommandString(size_t idx);
static const void* printReturnCommand(TextOutput& out, const void* _cmd);
static const void* printCommand(TextOutput& out, const void* _cmd); // This will result in a missing symbol failure if the IF_LOG_COMMANDS()
// conditionals don't get stripped... but that is probably what we want.
#if !LOG_NDEBUG
static const char *kReturnStrings[] = {
"BR_ERROR",
"BR_OK",
"BR_TRANSACTION",
"BR_REPLY",
"BR_ACQUIRE_RESULT",
"BR_DEAD_REPLY",
"BR_TRANSACTION_COMPLETE",
"BR_INCREFS",
"BR_ACQUIRE",
"BR_RELEASE",
"BR_DECREFS",
"BR_ATTEMPT_ACQUIRE",
"BR_NOOP",
"BR_SPAWN_LOOPER",
"BR_FINISHED",
"BR_DEAD_BINDER",
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
"BR_FAILED_REPLY"
}; static const char *kCommandStrings[] = {
"BC_TRANSACTION",
"BC_REPLY",
"BC_ACQUIRE_RESULT",
"BC_FREE_BUFFER",
"BC_INCREFS",
"BC_ACQUIRE",
"BC_RELEASE",
"BC_DECREFS",
"BC_INCREFS_DONE",
"BC_ACQUIRE_DONE",
"BC_ATTEMPT_ACQUIRE",
"BC_REGISTER_LOOPER",
"BC_ENTER_LOOPER",
"BC_EXIT_LOOPER",
"BC_REQUEST_DEATH_NOTIFICATION",
"BC_CLEAR_DEATH_NOTIFICATION",
"BC_DEAD_BINDER_DONE"
}; static const char* getReturnString(size_t idx)
{
if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[]))
return kReturnStrings[idx];
else
return "unknown";
} static const char* getCommandString(size_t idx)
{
if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[]))
return kCommandStrings[idx];
else
return "unknown";
} static const void* printBinderTransactionData(TextOutput& out, const void* data)
{
const binder_transaction_data* btd =
(const binder_transaction_data*)data;
if (btd->target.handle < ) {
/** want to print descriptors in decimal; guess based on value */
out << "target.desc=" << btd->target.handle;
} else {
out << "target.ptr=" << btd->target.ptr;
}
out << " (cookie " << btd->cookie << ")" << endl
<< "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
<< "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
<< " bytes)" << endl
<< "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
<< " bytes)";
return btd+;
} static const void* printReturnCommand(TextOutput& out, const void* _cmd)
{
static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[]);
const int32_t* cmd = (const int32_t*)_cmd;
int32_t code = *cmd++;
size_t cmdIndex = code & 0xff;
if (code == (int32_t) BR_ERROR) {
out << "BR_ERROR: " << (void*)(*cmd++) << endl;
return cmd;
} else if (cmdIndex >= N) {
out << "Unknown reply: " << code << endl;
return cmd;
}
out << kReturnStrings[cmdIndex]; switch (code) {
case BR_TRANSACTION:
case BR_REPLY: {
out << ": " << indent;
cmd = (const int32_t *)printBinderTransactionData(out, cmd);
out << dedent;
} break; case BR_ACQUIRE_RESULT: {
const int32_t res = *cmd++;
out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
} break; case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS: {
const int32_t b = *cmd++;
const int32_t c = *cmd++;
out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
} break; case BR_ATTEMPT_ACQUIRE: {
const int32_t p = *cmd++;
const int32_t b = *cmd++;
const int32_t c = *cmd++;
out << ": target=" << (void*)b << " (cookie " << (void*)c
<< "), pri=" << p;
} break; case BR_DEAD_BINDER:
case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
const int32_t c = *cmd++;
out << ": death cookie " << (void*)c;
} break; default:
// no details to show for: BR_OK, BR_DEAD_REPLY,
// BR_TRANSACTION_COMPLETE, BR_FINISHED
break;
} out << endl;
return cmd;
} static const void* printCommand(TextOutput& out, const void* _cmd)
{
static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[]);
const int32_t* cmd = (const int32_t*)_cmd;
int32_t code = *cmd++;
size_t cmdIndex = code & 0xff; if (cmdIndex >= N) {
out << "Unknown command: " << code << endl;
return cmd;
}
out << kCommandStrings[cmdIndex]; switch (code) {
case BC_TRANSACTION:
case BC_REPLY: {
out << ": " << indent;
cmd = (const int32_t *)printBinderTransactionData(out, cmd);
out << dedent;
} break; case BC_ACQUIRE_RESULT: {
const int32_t res = *cmd++;
out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
} break; case BC_FREE_BUFFER: {
const int32_t buf = *cmd++;
out << ": buffer=" << (void*)buf;
} break; case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS: {
const int32_t d = *cmd++;
out << ": desc=" << d;
} break; case BC_INCREFS_DONE:
case BC_ACQUIRE_DONE: {
const int32_t b = *cmd++;
const int32_t c = *cmd++;
out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
} break; case BC_ATTEMPT_ACQUIRE: {
const int32_t p = *cmd++;
const int32_t d = *cmd++;
out << ": desc=" << d << ", pri=" << p;
} break; case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
const int32_t h = *cmd++;
const int32_t c = *cmd++;
out << ": handle=" << h << " (death cookie " << (void*)c << ")";
} break; case BC_DEAD_BINDER_DONE: {
const int32_t c = *cmd++;
out << ": death cookie " << (void*)c;
} break; default:
// no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
// BC_EXIT_LOOPER
break;
} out << endl;
return cmd;
}
#endif static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = ;
static bool gShutdown = false;
static bool gDisableBackgroundScheduling = false; IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS) {
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
} if (gShutdown) return NULL; pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) {
if (pthread_key_create(&gTLS, threadDestructor) != ) {
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
} IPCThreadState* IPCThreadState::selfOrNull()
{
if (gHaveTLS) {
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
return st;
}
return NULL;
} void IPCThreadState::shutdown()
{
gShutdown = true; if (gHaveTLS) {
// XXX Need to wait for all thread pool threads to exit!
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
if (st) {
delete st;
pthread_setspecific(gTLS, NULL);
}
gHaveTLS = false;
}
} void IPCThreadState::disableBackgroundScheduling(bool disable)
{
gDisableBackgroundScheduling = disable;
} sp<ProcessState> IPCThreadState::process()
{
return mProcess;
} status_t IPCThreadState::clearLastError()
{
const status_t err = mLastError;
mLastError = NO_ERROR;
return err;
} int IPCThreadState::getCallingPid()
{
return mCallingPid;
} int IPCThreadState::getCallingUid()
{
return mCallingUid;
} int64_t IPCThreadState::clearCallingIdentity()
{
int64_t token = ((int64_t)mCallingUid<<) | mCallingPid;
clearCaller();
return token;
} void IPCThreadState::setStrictModePolicy(int32_t policy)
{
mStrictModePolicy = policy;
} int32_t IPCThreadState::getStrictModePolicy() const
{
return mStrictModePolicy;
} void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
{
mLastTransactionBinderFlags = flags;
} int32_t IPCThreadState::getLastTransactionBinderFlags() const
{
return mLastTransactionBinderFlags;
} void IPCThreadState::restoreCallingIdentity(int64_t token)
{
mCallingUid = (int)(token>>);
mCallingPid = (int)token;
} void IPCThreadState::clearCaller()
{
mCallingPid = getpid();
mCallingUid = getuid();
} void IPCThreadState::flushCommands()
{
if (mProcess->mDriverFD <= )
return;
talkWithDriver(false);
} void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); // This thread may have been spawned by a thread that was in the background
// scheduling group, so first we will make sure it is in the default/foreground
// one to avoid performing an initial transaction in the background.
androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT); status_t result;
do {
int32_t cmd; // When we've cleared the incoming command queue, process any pending derefs
if (mIn.dataPosition() >= mIn.dataSize()) {
size_t numPending = mPendingWeakDerefs.size();
if (numPending > ) {
for (size_t i = ; i < numPending; i++) {
RefBase::weakref_type* refs = mPendingWeakDerefs[i];
refs->decWeak(mProcess.get());
}
mPendingWeakDerefs.clear();
} numPending = mPendingStrongDerefs.size();
if (numPending > ) {
for (size_t i = ; i < numPending; i++) {
BBinder* obj = mPendingStrongDerefs[i];
obj->decStrong(mProcess.get());
}
mPendingStrongDerefs.clear();
}
} // now get the next command to be processed, waiting if necessary
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) continue;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
} result = executeCommand(cmd);
} // After executing the command, ensure that the thread is returned to the
// default cgroup before rejoining the pool. The driver takes care of
// restoring the priority, but doesn't do anything with cgroups so we
// need to take care of that here in userspace. Note that we do make
// sure to go in the foreground after executing a transaction, but
// there are other callbacks into user code that could have changed
// our group so we want to make absolutely sure it is put back.
androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT); // Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF); LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
(void*)pthread_self(), getpid(), (void*)result); mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
} void IPCThreadState::stopProcess(bool immediate)
{
//LOGI("**** STOPPING PROCESS");
flushCommands();
int fd = mProcess->mDriverFD;
mProcess->mDriverFD = -;
close(fd);
//kill(getpid(), SIGKILL);
} status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck(); flags |= TF_ACCEPT_FDS; IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
} if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == ? "READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
} if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
} if ((flags & TF_ONE_WAY) == ) {
#if 0
if (code == ) { // relayout
LOGI(">>>>>> CALLING transaction 4");
} else {
LOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == ) { // relayout
LOGI("<<<<<< RETURNING transaction 4");
} else {
LOGI("<<<<<< RETURNING transaction %d", code);
}
#endif IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
} return err;
} void IPCThreadState::incStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_ACQUIRE);
mOut.writeInt32(handle);
} void IPCThreadState::decStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_RELEASE);
mOut.writeInt32(handle);
} void IPCThreadState::incWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_INCREFS);
mOut.writeInt32(handle);
} void IPCThreadState::decWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_DECREFS);
mOut.writeInt32(handle);
} status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::attemptIncStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
mOut.writeInt32(); // xxx was thread priority
mOut.writeInt32(handle);
status_t result = UNKNOWN_ERROR; waitForResponse(NULL, &result); #if LOG_REFCOUNTS
printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
#endif return result;
} void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
{
#if LOG_REFCOUNTS
printf("IPCThreadState::expungeHandle(%ld)\n", handle);
#endif
self()->mProcess->expungeHandle(handle, binder);
} status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writeInt32((int32_t)proxy);
return NO_ERROR;
} status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writeInt32((int32_t)proxy);
return NO_ERROR;
} IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mMyThreadId(androidGetTid()),
mStrictModePolicy(),
mLastTransactionBinderFlags()
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity();
mOut.setDataCapacity();
} IPCThreadState::~IPCThreadState()
{
} status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
status_t err;
status_t statusBuffer;
err = writeTransactionData(BC_REPLY, flags, -, , reply, &statusBuffer);
if (err < NO_ERROR) return err; return waitForResponse(NULL, NULL);
} status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err; while () {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == ) continue; cmd = mIn.readInt32(); IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
} switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break; case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish; case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish; case BR_ACQUIRE_RESULT:
{
LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish; case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish; if (reply) {
if ((tr.flags & TF_STATUS_CODE) == ) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t),
freeBuffer, this);
} else {
err = *static_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), this);
}
} else {
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), this);
continue;
}
}
goto finish; default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
} finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
} return err;
} status_t IPCThreadState::talkWithDriver(bool doReceive)
{
LOG_ASSERT(mProcess->mDriverFD >= , "Binder driver is not opened"); binder_write_read bwr; // Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize(); // We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : ; bwr.write_size = outAvail;
bwr.write_buffer = (long unsigned int)mOut.data(); // This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (long unsigned int)mIn.data();
} else {
bwr.read_size = ;
} IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != ) {
alog << "Sending commands to driver: " << indent;
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds)+bwr.write_size;
alog << HexDump(cmds, bwr.write_size) << endl;
while (cmds < end) cmds = printCommand(alog, cmds);
alog << dedent;
}
alog << "Size of receive buffer: " << bwr.read_size
<< ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
} // Return immediately if there is nothing to do.
if ((bwr.write_size == ) && (bwr.read_size == )) return NO_ERROR; bwr.write_consumed = ;
bwr.read_consumed = ;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(HAVE_ANDROID_OS)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= )
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR); IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
} if (err >= NO_ERROR) {
if (bwr.write_consumed > ) {
if (bwr.write_consumed < (ssize_t)mOut.dataSize())
mOut.remove(, bwr.write_consumed);
else
mOut.setDataSize();
}
if (bwr.read_consumed > ) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition();
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
} return err;
} status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr; tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = ;
tr.sender_pid = ;
tr.sender_euid = ; const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = statusBuffer;
tr.offsets_size = ;
tr.data.ptr.offsets = NULL;
} else {
return (mLastError = err);
} mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr)); return NO_ERROR;
} sp<BBinder> the_context_object; void setTheContextObject(sp<BBinder> obj)
{
the_context_object = obj;
} status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR; switch (cmd) {
case BR_ERROR:
result = mIn.readInt32();
break; case BR_OK:
break; case BR_ACQUIRE:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
LOG_ASSERT(refs->refBase() == obj,
"BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
refs, obj, refs->refBase());
obj->incStrong(mProcess.get());
IF_LOG_REMOTEREFS() {
LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
obj->printRefs();
}
mOut.writeInt32(BC_ACQUIRE_DONE);
mOut.writeInt32((int32_t)refs);
mOut.writeInt32((int32_t)obj);
break; case BR_RELEASE:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
LOG_ASSERT(refs->refBase() == obj,
"BR_RELEASE: object %p does not match cookie %p (expected %p)",
refs, obj, refs->refBase());
IF_LOG_REMOTEREFS() {
LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
obj->printRefs();
}
mPendingStrongDerefs.push(obj);
break; case BR_INCREFS:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
refs->incWeak(mProcess.get());
mOut.writeInt32(BC_INCREFS_DONE);
mOut.writeInt32((int32_t)refs);
mOut.writeInt32((int32_t)obj);
break; case BR_DECREFS:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32();
// NOTE: This assertion is not valid, because the object may no
// longer exist (thus the (BBinder*)cast above resulting in a different
// memory address).
//LOG_ASSERT(refs->refBase() == obj,
// "BR_DECREFS: object %p does not match cookie %p (expected %p)",
// refs, obj, refs->refBase());
mPendingWeakDerefs.push(refs);
break; case BR_ATTEMPT_ACQUIRE:
refs = (RefBase::weakref_type*)mIn.readInt32();
obj = (BBinder*)mIn.readInt32(); {
const bool success = refs->attemptIncStrong(mProcess.get());
LOG_ASSERT(success && refs->refBase() == obj,
"BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
refs, obj, refs->refBase()); mOut.writeInt32(BC_ACQUIRE_RESULT);
mOut.writeInt32((int32_t)success);
}
break; case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
LOG_ASSERT(result == NO_ERROR,
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break; Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), freeBuffer, this); const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid; mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid; int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
if (curPrio > ANDROID_PRIORITY_NORMAL) {
// We have inherited a reduced priority from the caller, but do not
// want to run in that state in this process. The driver set our
// priority already (though not our scheduling class), so bounce
// it back to the default before invoking the transaction.
setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
}
} else {
if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
// We want to use the inherited priority from the caller.
// Ensure this thread is in the background scheduling class,
// since the driver won't modify scheduling classes for us.
// The scheduling group is reset to default by the caller
// once this method returns after the transaction is complete.
androidSetThreadSchedulingGroup(mMyThreadId,
ANDROID_TGROUP_BG_NONINTERACT);
}
} //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); Parcel reply;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_TRANSACTION thr " << (void*)pthread_self()
<< " / obj " << tr.target.ptr << " / code "
<< TypeCode(tr.code) << ": " << indent << buffer
<< dedent << endl
<< "Data addr = "
<< reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
<< ", offsets addr="
<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
}
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error); } else {
const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
} //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
// mCallingPid, origPid, origUid); if ((tr.flags & TF_ONE_WAY) == ) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
sendReply(reply, );
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
} mCallingPid = origPid;
mCallingUid = origUid; IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
<< tr.target.ptr << ": " << indent << reply << dedent << endl;
} }
break; case BR_DEAD_BINDER:
{
BpBinder *proxy = (BpBinder*)mIn.readInt32();
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writeInt32((int32_t)proxy);
} break; case BR_CLEAR_DEATH_NOTIFICATION_DONE:
{
BpBinder *proxy = (BpBinder*)mIn.readInt32();
proxy->getWeakRefs()->decWeak(proxy);
} break; case BR_FINISHED:
result = TIMED_OUT;
break; case BR_NOOP:
break; case BR_SPAWN_LOOPER:
mProcess->spawnPooledThread(false);
break; default:
printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
result = UNKNOWN_ERROR;
break;
} if (result != NO_ERROR) {
mLastError = result;
} return result;
} void IPCThreadState::threadDestructor(void *st)
{
IPCThreadState* const self = static_cast<IPCThreadState*>(st);
if (self) {
self->flushCommands();
#if defined(HAVE_ANDROID_OS)
ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, );
#endif
delete self;
}
} void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
const size_t* objects, size_t objectsSize,
void* cookie)
{
//LOGI("Freeing parcel %p", &parcel);
IF_LOG_COMMANDS() {
alog << "Writing BC_FREE_BUFFER for " << data << endl;
}
LOG_ASSERT(data != NULL, "Called with NULL data");
if (parcel != NULL) parcel->closeFileDescriptors();
IPCThreadState* state = self();
state->mOut.writeInt32(BC_FREE_BUFFER);
state->mOut.writeInt32((int32_t)data);
} }; // namespace androidIPCThreadState
- 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 androidIServiceManager.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 playJNI 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 androidBpMediaPlayer
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的更多相关文章
- Android -- com.android.providers.media,external.db
external.db android是管理多媒体文件(音频.视频.图片)的信息是在/data/data/com.android.providers.media下的数据库文件external.db. ...
- 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 ...
- Android开发 ---Media
1.ctivity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...
- android stream media
http://www.cnblogs.com/skyseraph/archive/2012/03/31/2427593.html http://www.cnblogs.com/lingyunhu/p/ ...
- Android学习笔记——文件路径(/mnt/sdcard/...)、Uri(content://media/external/...)学习
一.URI 通用资源标志符(Universal Resource Identifier, 简称"URI"). Uri代表要操作的数据,Android上可用的每种资源 - 图像.视频 ...
- Android MediaStore与Media.EXTERNAL_CONTENT_URI
MediaStore这个类是Android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取.这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,andro ...
- Android 文件路径(/mnt/sdcard/...)、Uri(content://media/external/...)
一.URI 通用资源标志符(Universal Resource Identifier, 简称"URI"). Uri代表要操作的数据,Android上可用的每种资源 - 图像.视频 ...
- Android Lint Checks
Android Lint Checks Here are the current list of checks that lint performs as of Android Studio 2.3 ...
- Android进程整理
一.概括 系统启动架构图: 上图在Android系统-开篇中有讲解,是从Android系统启动的角度来分析,本文是从进程/线程的视角来分析该问题. 1.1 父进程 在所有进程中,以父进程的姿态存在的进 ...
随机推荐
- 「NOI.AC」Leaves 线段树合并
题目描述 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有\(n\)个叶子节点,满足这些权值为\(1\dots n\)的一个排列).可以任意交换每个非叶子节点的左右孩子. ...
- springboot整合springtask
在使用 springmvc 中,一般的定时任务是使用 job 或者 quartz 或者timer来实现,但是使用它们的时候比较麻烦,会在 xml 文件中配置很多, springboot 的定时任务比较 ...
- linux中tomcat内存溢出
刚开始测试服务器与线上后台都不能上传10分钟以上的视频,后来只要是视频就不能上传,进入服务器查日志得到如下错误: Caused by: java.lang.OutOfMemoryError: Java ...
- STM32F030 定时器多次溢出才触发中断的问题
前言 最近在调试项目过程中,用了 STM32F030 的定时器 16 作为系统时钟,1ms 触发一次中断,过程中遇到一些值得记录的问题. 记录 STM32F030 中定时器 16 的初始化配置如下 v ...
- poj3111 选取物品(二分+贪心)
题目传送门 题意就是,n个物品,从中选取k个,要按照那个公式所取的值最大. 思路:最大化平均值的时候首先想到的就是二分, 我们设G(x) 为单位的重量不小于X, 我们的目标就是要找到满足条件的最大的X ...
- javascript中的一元操作符
题目如下: var s1 = "01"; var s2 = "1.1"; var s3 = "z"; var b = false; var ...
- 2015苏州大学ACM-ICPC集训队选拔赛(1) 1007
连通图 Time Limit : 3000/1000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other) Total Submissio ...
- sqlserver 事务日志
预写式日志(Write-Ahead Logging (WAL)) --在数据写入到数据库之前,先写入到日志. 1.”Begin Tran”记录 -> 缓冲区 2. 日志 ...
- UML箭头
继承(泛化):用实线空心三角箭头表示 实现(接口):用虚线空心三角形箭头标示 依赖:虚线箭头,类A指向类B 方法参数需要传入另一个类的对象,就表示依赖这个类 关联:实线箭头,类A指向类B 一个类的全局 ...
- 问题解决Determine IP information for eth0.. no link present check cable
网上方法都没有解决:简单粗暴编辑里还原了默认设置OK了 网上方法1 一般解决办法: 第一步: 到/etc/sysconfig/network-scripts/ifcfg-eth<n>/et ...