blob: 63c234fc061d3ec5695e0bb8fff6f90ddbb67b07 [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/emulation/AndroidPipe.h"
#include "android/opengles.h"
#include <assert.h>
#include <atomic>
#include <memory>
namespace android {
namespace opengl {
namespace {
// GLProcessPipe is a pipe service that is used for releasing graphics resources
// per guest process. At the time being, guest processes can acquire host color
// buffer handles / EGLImage handles and they need to be properly released when
// guest process exits unexpectedly. This class is used to detect if guest
// process exits, so that a proper cleanup function can be called.
// It is done by setting up a pipe per guest process before acquiring color
// buffer handles. When guest process exits, the pipe will be closed, and
// onGuestClose() will trigger the cleanup path.
class GLProcessPipe : public AndroidPipe {
public:
//////////////////////////////////////////////////////////////////////////
// The pipe service class for this implementation.
class Service : public AndroidPipe::Service {
public:
Service() : AndroidPipe::Service("GLProcessPipe") {}
bool canLoad() const override { return true; }
AndroidPipe* create(void* hwPipe, const char* args) override {
return new GLProcessPipe(hwPipe, this);
}
AndroidPipe* load(void* hwPipe, const char* args,
base::Stream* stream) override {
return new GLProcessPipe(hwPipe, this, stream);
}
void preLoad(base::Stream* stream) override {
GLProcessPipe::s_headId.store(stream->getBe64());
}
void preSave(base::Stream* stream) override {
stream->putBe64(GLProcessPipe::s_headId.load());
}
};
GLProcessPipe(void* hwPipe, Service* service,
base::Stream* loadStream = nullptr)
: AndroidPipe(hwPipe, service) {
if (loadStream) {
m_uniqueId = loadStream->getBe64();
m_hasData = (loadStream->getByte() != 0);
} else {
m_uniqueId = ++s_headId;
}
}
void onSave(base::Stream* stream) override {
stream->putBe64(m_uniqueId);
stream->putByte(m_hasData ? 1 : 0);
}
void onGuestClose(PipeCloseReason reason) override {
android_cleanupProcGLObjects(m_uniqueId);
delete this;
}
unsigned onGuestPoll() const override {
return PIPE_POLL_IN | PIPE_POLL_OUT;
}
int onGuestRecv(AndroidPipeBuffer* buffers, int numBuffers) override {
assert(buffers[0].size >= 8);
if (m_hasData) {
m_hasData = false;
memcpy(buffers[0].data, (const char*)&m_uniqueId, sizeof(m_uniqueId));
return sizeof(m_uniqueId);
} else {
return 0;
}
}
int onGuestSend(const AndroidPipeBuffer* buffers,
int numBuffers,
void** newPipePtr) override {
// The guest is supposed to send us a confirm code first. The code is
// 100 (4 byte integer).
assert(buffers[0].size >= 4);
int32_t confirmInt = *((int32_t*)buffers[0].data);
assert(confirmInt == 100);
(void)confirmInt;
m_hasData = true;
return buffers[0].size;
}
void onGuestWantWakeOn(int flags) override {}
private:
// An identifier for the guest process corresponding to this pipe.
// With very high probability, all currently-active processes have unique
// identifiers, since the IDs are assigned sequentially from a 64-bit ID
// space.
// Please change it if you ever have a use case that exhausts them
uint64_t m_uniqueId;
bool m_hasData = false;
static std::atomic<uint64_t> s_headId;
};
std::atomic<uint64_t> GLProcessPipe::s_headId {0};
}
void registerGLProcessPipeService() {
AndroidPipe::Service::add(std::make_unique<GLProcessPipe::Service>());
}
}
}