A是B的代理,对B的访问都可以通过对A的访问来实现。为什么要这样?因为对B的访问可能需要跨进程,可能需要复杂的逻辑判断,可能需要。。。总之比较麻烦,所以B为了提供给别人一个好用的接口,就创建了自己的代理A。
在大名鼎鼎的Binder通信里,就是用Bp来做Bn的代理,Bp可以放在访问者进程里,从而封装了麻烦的跨进程调用。
还有一个例子是AudioTrack和AudioFlinger在操作匿名共享内存的时候,使用了ClientProxy,ServerProxy。我们可以看到,它们提供的接口都是类似的,但是却封装了复杂的循环buffer前后指针判断逻辑和跨进程操作。
{
protected:
ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
bool isOut, bool clientInServer);
public:
virtual ~ServerProxy() { }
// Obtain a buffer with filled frames (writing) or empty frames (reading).
// It is permitted to call obtainBuffer() multiple times in succession, without any intervening
// calls to releaseBuffer(). In that case, the final obtainBuffer() is the one that effectively
// sets or extends the unreleased frame count.
// Always non-blocking.
// On entry:
// buffer->mFrameCount should be initialized to maximum number of desired frames,
// which must be > 0.
// buffer->mNonContig is unused.
// buffer->mRaw is unused.
// ackFlush is true iff being called from Track::start to acknowledge a pending flush.
// On exit:
// buffer->mFrameCount has the actual number of contiguous available frames,
// which is always 0 when the return status != NO_ERROR.
// buffer->mNonContig is the number of additional non-contiguous available frames.
// buffer->mRaw is a pointer to the first available frame,
// or NULL when buffer->mFrameCount == 0.
// The return status is one of:
// NO_ERROR Success, buffer->mFrameCount > 0.
// WOULD_BLOCK No frames are available.
// NO_INIT Shared memory is corrupt.
virtual status_t obtainBuffer(Buffer* buffer, bool ackFlush = false);
// Release (some of) the frames last obtained.
// On entry, buffer->mFrameCount should have the number of frames to release,
// which must (cumulatively) be <= the number of frames last obtained but not yet released.
// It is permitted to call releaseBuffer() multiple times to release the frames in chunks.
// buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer().
// On exit:
// buffer->mFrameCount is zero.
// buffer->mRaw is NULL.
virtual void releaseBuffer(Buffer* buffer);
protected:
size_t mAvailToClient; // estimated frames available to client prior to releaseBuffer()
int32_t mFlush; // our copy of cblk->u.mStreaming.mFlush, for streaming output only
}
// Proxy seen by AudioTrack client and AudioRecord client
class ClientProxy : public Proxy {
public:
ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
bool isOut, bool clientInServer);
virtual ~ClientProxy() { }
static const struct timespec kForever;
static const struct timespec kNonBlocking;
// Obtain a buffer with filled frames (reading) or empty frames (writing).
// It is permitted to call obtainBuffer() multiple times in succession, without any intervening
// calls to releaseBuffer(). In that case, the final obtainBuffer() is the one that effectively
// sets or extends the unreleased frame count.
// On entry:
// buffer->mFrameCount should be initialized to maximum number of desired frames,
// which must be > 0.
// buffer->mNonContig is unused.
// buffer->mRaw is unused.
// requested is the requested timeout in local monotonic delta time units:
// NULL or &kNonBlocking means non-blocking (zero timeout).
// &kForever means block forever (infinite timeout).
// Other values mean a specific timeout in local monotonic delta time units.
// elapsed is a pointer to a location that will hold the total local monotonic time that
// elapsed while blocked, or NULL if not needed.
// On exit:
// buffer->mFrameCount has the actual number of contiguous available frames,
// which is always 0 when the return status != NO_ERROR.
// buffer->mNonContig is the number of additional non-contiguous available frames.
// buffer->mRaw is a pointer to the first available frame,
// or NULL when buffer->mFrameCount == 0.
// The return status is one of:
// NO_ERROR Success, buffer->mFrameCount > 0.
// WOULD_BLOCK Non-blocking mode and no frames are available.
// TIMED_OUT Timeout occurred before any frames became available.
// This can happen even for infinite timeout, due to a spurious wakeup.
// In this case, the caller should investigate and then re-try as appropriate.
// DEAD_OBJECT Server has died or invalidated, caller should destroy this proxy and re-create.
// -EINTR Call has been interrupted. Look around to see why, and then perhaps try again.
// NO_INIT Shared memory is corrupt.
// Assertion failure on entry, if buffer == NULL or buffer->mFrameCount == 0.
status_t obtainBuffer(Buffer* buffer, const struct timespec *requested = NULL,
struct timespec *elapsed = NULL);
// Release (some of) the frames last obtained.
// On entry, buffer->mFrameCount should have the number of frames to release,
// which must (cumulatively) be <= the number of frames last obtained but not yet released.
// buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer().
// It is permitted to call releaseBuffer() multiple times to release the frames in chunks.
// On exit:
// buffer->mFrameCount is zero.
// buffer->mRaw is NULL.
void releaseBuffer(Buffer* buffer);
// Call after detecting server's death
void binderDied();
// Call to force an obtainBuffer() to return quickly with -EINTR
void interrupt();
size_t getPosition() {
return mEpoch + mCblk->mServer;
}
void setEpoch(size_t epoch) {
mEpoch = epoch;
}
void setMinimum(size_t minimum) {
// This can only happen on a 64-bit client
if (minimum > UINT32_MAX) {
minimum = UINT32_MAX;
}
mCblk->mMinimum = (uint32_t) minimum;
}
// Return the number of frames that would need to be obtained and released
// in order for the client to be aligned at start of buffer
virtual size_t getMisalignment();
size_t getEpoch() const {
return mEpoch;
}
size_t getFramesFilled();
private:
size_t mEpoch;
};