| // 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>()); |
| } |
| |
| } |
| } |