1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "../AndroidPipe.h"
16
17 #include "base/Lock.h"
18 #include "../opengles.h"
19 #include <assert.h>
20 #include <atomic>
21 #include <memory>
22 #include <unordered_set>
23
24 #include <string.h>
25
26 using android::base::AutoLock;
27 using android::base::Lock;
28
29 namespace android {
30 namespace opengl {
31
32 struct ProcessPipeIdRegistry {
33 Lock lock;
34 std::unordered_set<uint64_t> ids;
35 };
36
37 static ProcessPipeIdRegistry sRegistry;
38
sIdExistsInRegistry(uint64_t id)39 static bool sIdExistsInRegistry(uint64_t id) {
40 AutoLock lock(sRegistry.lock);
41 auto it = sRegistry.ids.find(id);
42 return it != sRegistry.ids.end();
43 }
44
45 namespace {
46
47 // GLProcessPipe is a pipe service that is used for releasing graphics resources
48 // per guest process. At the time being, guest processes can acquire host color
49 // buffer handles / EGLImage handles and they need to be properly released when
50 // guest process exits unexpectedly. This class is used to detect if guest
51 // process exits, so that a proper cleanup function can be called.
52
53 // It is done by setting up a pipe per guest process before acquiring color
54 // buffer handles. When guest process exits, the pipe will be closed, and
55 // onGuestClose() will trigger the cleanup path.
56
57 class GLProcessPipe : public AndroidPipe {
58 public:
59 //////////////////////////////////////////////////////////////////////////
60 // The pipe service class for this implementation.
61 class Service : public AndroidPipe::Service {
62 public:
Service()63 Service() : AndroidPipe::Service("GLProcessPipe") {}
64
canLoad() const65 bool canLoad() const override { return true; }
66
create(void * hwPipe,const char * args,enum AndroidPipeFlags flags)67 AndroidPipe* create(void* hwPipe, const char* args, enum AndroidPipeFlags flags) override {
68 return new GLProcessPipe(hwPipe, this, flags);
69 }
70
load(void * hwPipe,const char * args,base::Stream * stream)71 AndroidPipe* load(void* hwPipe, const char* args,
72 base::Stream* stream) override {
73 return new GLProcessPipe(hwPipe, this, (AndroidPipeFlags)0, stream);
74 }
75
preLoad(base::Stream * stream)76 void preLoad(base::Stream* stream) override {
77 GLProcessPipe::s_headId.store(stream->getBe64());
78 }
79
preSave(base::Stream * stream)80 void preSave(base::Stream* stream) override {
81 stream->putBe64(GLProcessPipe::s_headId.load());
82 }
83 };
84
GLProcessPipe(void * hwPipe,Service * service,enum AndroidPipeFlags flags,base::Stream * loadStream=nullptr)85 GLProcessPipe(void* hwPipe, Service* service, enum AndroidPipeFlags flags,
86 base::Stream* loadStream = nullptr)
87 : AndroidPipe(hwPipe, service) {
88 if (loadStream) {
89 m_uniqueId = loadStream->getBe64();
90 m_hasData = (loadStream->getByte() != 0);
91 } else {
92 if (flags & ANDROID_PIPE_VIRTIO_GPU_BIT) {
93 m_uniqueId = (uint64_t)(uintptr_t)hwPipe;
94 s_headId = m_uniqueId;
95 } else {
96 m_uniqueId = ++s_headId;
97 }
98 }
99 AutoLock lock(sRegistry.lock);
100 sRegistry.ids.insert(m_uniqueId);
101 }
102
~GLProcessPipe()103 ~GLProcessPipe() {
104 AutoLock lock(sRegistry.lock);
105 sRegistry.ids.erase(m_uniqueId);
106 }
107
onSave(base::Stream * stream)108 void onSave(base::Stream* stream) override {
109 stream->putBe64(m_uniqueId);
110 stream->putByte(m_hasData ? 1 : 0);
111 }
112
onGuestClose(PipeCloseReason reason)113 void onGuestClose(PipeCloseReason reason) override {
114 if (sIdExistsInRegistry(m_uniqueId)) {
115 android_cleanupProcGLObjects(m_uniqueId);
116 }
117 delete this;
118 }
119
onGuestPoll() const120 unsigned onGuestPoll() const override {
121 return PIPE_POLL_IN | PIPE_POLL_OUT;
122 }
123
onGuestRecv(AndroidPipeBuffer * buffers,int numBuffers)124 int onGuestRecv(AndroidPipeBuffer* buffers, int numBuffers) override {
125 assert(buffers[0].size >= 8);
126 if (m_hasData) {
127 m_hasData = false;
128 memcpy(buffers[0].data, (const char*)&m_uniqueId, sizeof(m_uniqueId));
129 return sizeof(m_uniqueId);
130 } else {
131 return 0;
132 }
133 }
134
onGuestSend(const AndroidPipeBuffer * buffers,int numBuffers,void ** newPipePtr)135 int onGuestSend(const AndroidPipeBuffer* buffers,
136 int numBuffers,
137 void** newPipePtr) override {
138 // The guest is supposed to send us a confirm code first. The code is
139 // 100 (4 byte integer).
140 assert(buffers[0].size >= 4);
141 int32_t confirmInt = *((int32_t*)buffers[0].data);
142 assert(confirmInt == 100);
143 (void)confirmInt;
144 m_hasData = true;
145 return buffers[0].size;
146 }
147
onGuestWantWakeOn(int flags)148 void onGuestWantWakeOn(int flags) override {}
149
150 private:
151 // An identifier for the guest process corresponding to this pipe.
152 // With very high probability, all currently-active processes have unique
153 // identifiers, since the IDs are assigned sequentially from a 64-bit ID
154 // space.
155 // Please change it if you ever have a use case that exhausts them
156 uint64_t m_uniqueId;
157 bool m_hasData = false;
158 static std::atomic<uint64_t> s_headId;
159
160 };
161
162 std::atomic<uint64_t> GLProcessPipe::s_headId {0};
163
164 }
165
registerGLProcessPipeService()166 void registerGLProcessPipeService() {
167 AndroidPipe::Service::add(std::make_unique<GLProcessPipe::Service>());
168 }
169
forEachProcessPipeId(std::function<void (uint64_t)> f)170 void forEachProcessPipeId(std::function<void(uint64_t)> f) {
171 AutoLock lock(sRegistry.lock);
172 for (auto id: sRegistry.ids) {
173 f(id);
174 }
175 }
176
forEachProcessPipeIdRunAndErase(std::function<void (uint64_t)> f)177 void forEachProcessPipeIdRunAndErase(std::function<void(uint64_t)> f) {
178 AutoLock lock(sRegistry.lock);
179 auto it = sRegistry.ids.begin();
180 while (it != sRegistry.ids.end()) {
181 f(*it);
182 it = sRegistry.ids.erase(it);
183 }
184 }
185
186 }
187 }
188