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 <assert.h>
16 #include <atomic>
17 #include <limits>
18 #include <memory>
19 #include <string.h>
20 #include <unordered_set>
21 
22 #include "aemu/base/synchronization/Lock.h"
23 #include "host-common/AndroidPipe.h"
24 #include "host-common/opengles.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                 // virtio-gpu uses context creation to manage process resources
94                 return;
95             } else {
96                 m_uniqueId = ++s_headId;
97             }
98         }
99         AutoLock lock(sRegistry.lock);
100         sRegistry.ids.insert(m_uniqueId);
101         android_onGuestGraphicsProcessCreate(m_uniqueId);
102     }
103 
~GLProcessPipe()104     ~GLProcessPipe() {
105         AutoLock lock(sRegistry.lock);
106         sRegistry.ids.erase(m_uniqueId);
107     }
108 
onSave(base::Stream * stream)109     void onSave(base::Stream* stream) override {
110         stream->putBe64(m_uniqueId);
111         stream->putByte(m_hasData ? 1 : 0);
112     }
113 
onGuestClose(PipeCloseReason reason)114     void onGuestClose(PipeCloseReason reason) override {
115         if (sIdExistsInRegistry(m_uniqueId)) {
116             android_cleanupProcGLObjects(m_uniqueId);
117         }
118         delete this;
119     }
120 
onGuestPoll() const121     unsigned onGuestPoll() const override {
122         return PIPE_POLL_IN | PIPE_POLL_OUT;
123     }
124 
onGuestRecv(AndroidPipeBuffer * buffers,int numBuffers)125     int onGuestRecv(AndroidPipeBuffer* buffers, int numBuffers) override {
126         assert(buffers[0].size >= 8);
127         if (m_hasData) {
128             m_hasData = false;
129             memcpy(buffers[0].data, (const char*)&m_uniqueId, sizeof(m_uniqueId));
130             return sizeof(m_uniqueId);
131         } else {
132             return 0;
133         }
134     }
135 
onGuestSend(const AndroidPipeBuffer * buffers,int numBuffers,void ** newPipePtr)136     int onGuestSend(const AndroidPipeBuffer* buffers,
137                             int numBuffers,
138                             void** newPipePtr) override {
139         // The guest is supposed to send us a confirm code first. The code is
140         // 100 (4 byte integer).
141         assert(buffers[0].size >= 4);
142         int32_t confirmInt = *((int32_t*)buffers[0].data);
143         assert(confirmInt == 100);
144         (void)confirmInt;
145         m_hasData = true;
146         return buffers[0].size;
147     }
148 
onGuestWantWakeOn(int flags)149     void onGuestWantWakeOn(int flags) override {}
150 
151 private:
152     // An identifier for the guest process corresponding to this pipe.
153     // With very high probability, all currently-active processes have unique
154     // identifiers, since the IDs are assigned sequentially from a 64-bit ID
155     // space.
156     // Please change it if you ever have a use case that exhausts them
157     uint64_t m_uniqueId = std::numeric_limits<uint64_t>::max();
158     bool m_hasData = false;
159     static std::atomic<uint64_t> s_headId;
160 
161 };
162 
163 std::atomic<uint64_t> GLProcessPipe::s_headId {0};
164 
165 }
166 
registerGLProcessPipeService()167 void registerGLProcessPipeService() {
168     AndroidPipe::Service::add(std::make_unique<GLProcessPipe::Service>());
169 }
170 
forEachProcessPipeId(std::function<void (uint64_t)> f)171 void forEachProcessPipeId(std::function<void(uint64_t)> f) {
172     AutoLock lock(sRegistry.lock);
173     for (auto id: sRegistry.ids) {
174         f(id);
175     }
176 }
177 
forEachProcessPipeIdRunAndErase(std::function<void (uint64_t)> f)178 void forEachProcessPipeIdRunAndErase(std::function<void(uint64_t)> f) {
179     AutoLock lock(sRegistry.lock);
180     auto it = sRegistry.ids.begin();
181     while (it != sRegistry.ids.end()) {
182         f(*it);
183         it = sRegistry.ids.erase(it);
184     }
185 }
186 
187 }
188 }
189