1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <aidl/android/crosvm/BnCrosvmAndroidDisplayService.h>
18 #include <aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.h>
19 #include <android/binder_manager.h>
20 #include <android/binder_process.h>
21 #include <system/graphics.h> // for HAL_PIXEL_FORMAT_*
22 
23 #include <condition_variable>
24 #include <memory>
25 #include <mutex>
26 
27 using aidl::android::crosvm::BnCrosvmAndroidDisplayService;
28 using aidl::android::system::virtualizationservice_internal::IVirtualizationServiceInternal;
29 using aidl::android::view::Surface;
30 
31 namespace {
32 
33 class DisplayService : public BnCrosvmAndroidDisplayService {
34 public:
35     DisplayService() = default;
36     virtual ~DisplayService() = default;
37 
setSurface(Surface * surface,bool forCursor)38     ndk::ScopedAStatus setSurface(Surface* surface, bool forCursor) override {
39         {
40             std::lock_guard lk(mSurfaceReadyMutex);
41             if (forCursor) {
42                 mCursorSurface = std::make_unique<Surface>(surface->release());
43             } else {
44                 mSurface = std::make_unique<Surface>(surface->release());
45             }
46         }
47         mSurfaceReady.notify_all();
48         return ::ndk::ScopedAStatus::ok();
49     }
50 
removeSurface(bool forCursor)51     ndk::ScopedAStatus removeSurface(bool forCursor) override {
52         {
53             std::lock_guard lk(mSurfaceReadyMutex);
54             if (forCursor) {
55                 mCursorSurface = nullptr;
56             } else {
57                 mSurface = nullptr;
58             }
59         }
60         mSurfaceReady.notify_all();
61         return ::ndk::ScopedAStatus::ok();
62     }
63 
getSurface(bool forCursor)64     Surface* getSurface(bool forCursor) {
65         std::unique_lock lk(mSurfaceReadyMutex);
66         if (forCursor) {
67             mSurfaceReady.wait(lk, [this] { return mCursorSurface != nullptr; });
68             return mCursorSurface.get();
69         } else {
70             mSurfaceReady.wait(lk, [this] { return mSurface != nullptr; });
71             return mSurface.get();
72         }
73     }
getCursorStream()74     ndk::ScopedFileDescriptor& getCursorStream() { return mCursorStream; }
setCursorStream(const ndk::ScopedFileDescriptor & in_stream)75     ndk::ScopedAStatus setCursorStream(const ndk::ScopedFileDescriptor& in_stream) {
76         mCursorStream = ndk::ScopedFileDescriptor(dup(in_stream.get()));
77         return ::ndk::ScopedAStatus::ok();
78     }
79 
80 private:
81     std::condition_variable mSurfaceReady;
82     std::mutex mSurfaceReadyMutex;
83     std::unique_ptr<Surface> mSurface;
84     std::unique_ptr<Surface> mCursorSurface;
85     ndk::ScopedFileDescriptor mCursorStream;
86 };
87 
88 } // namespace
89 
90 typedef void (*ErrorCallback)(const char* message);
91 
92 struct AndroidDisplayContext {
93     std::shared_ptr<IVirtualizationServiceInternal> virt_service;
94     std::shared_ptr<DisplayService> disp_service;
95     ErrorCallback error_callback;
96 
AndroidDisplayContextAndroidDisplayContext97     AndroidDisplayContext(ErrorCallback cb) : error_callback(cb) {
98         auto disp_service = ::ndk::SharedRefBase::make<DisplayService>();
99 
100         // Creates DisplayService and register it to the virtualizationservice. This is needed
101         // because this code is executed inside of crosvm which runs as an app. Apps are not allowed
102         // to register a service to the service manager.
103         auto virt_service = IVirtualizationServiceInternal::fromBinder(ndk::SpAIBinder(
104                 AServiceManager_waitForService("android.system.virtualizationservice")));
105         if (virt_service == nullptr) {
106             errorf("Failed to find virtualization service");
107             return;
108         }
109         auto status = virt_service->setDisplayService(disp_service->asBinder());
110         if (!status.isOk()) {
111             errorf("Failed to register display service");
112             return;
113         }
114 
115         this->virt_service = virt_service;
116         this->disp_service = disp_service;
117         ABinderProcess_startThreadPool();
118     }
119 
~AndroidDisplayContextAndroidDisplayContext120     ~AndroidDisplayContext() {
121         if (virt_service == nullptr) {
122             errorf("Not connected to virtualization service");
123             return;
124         }
125         auto status = this->virt_service->clearDisplayService();
126         if (!status.isOk()) {
127             errorf("Failed to clear display service");
128         }
129     }
130 
errorfAndroidDisplayContext131     void errorf(const char* format, ...) {
132         char buffer[1024];
133 
134         va_list vararg;
135         va_start(vararg, format);
136         vsnprintf(buffer, sizeof(buffer), format, vararg);
137         va_end(vararg);
138 
139         error_callback(buffer);
140     }
141 };
142 
create_android_display_context(const char *,ErrorCallback error_callback)143 extern "C" struct AndroidDisplayContext* create_android_display_context(
144         const char*, ErrorCallback error_callback) {
145     return new AndroidDisplayContext(error_callback);
146 }
147 
destroy_android_display_context(struct AndroidDisplayContext * ctx)148 extern "C" void destroy_android_display_context(struct AndroidDisplayContext* ctx) {
149     delete ctx;
150 }
151 
create_android_surface(struct AndroidDisplayContext * ctx,uint32_t width,uint32_t height,bool for_cursor)152 extern "C" ANativeWindow* create_android_surface(struct AndroidDisplayContext* ctx, uint32_t width,
153                                                  uint32_t height, bool for_cursor) {
154     if (ctx->disp_service == nullptr) {
155         ctx->errorf("Display service was not created");
156         return nullptr;
157     }
158     // Note: crosvm always uses BGRA8888 or BGRX8888. See devices/src/virtio/gpu/mod.rs in crosvm
159     // where the SetScanoutBlob command is handled. Let's use BGRA not BGRX with a hope that we will
160     // need alpha blending for the cursor surface.
161     int format = HAL_PIXEL_FORMAT_BGRA_8888;
162     ANativeWindow* surface = ctx->disp_service->getSurface(for_cursor)->get(); // this can block
163     if (ANativeWindow_setBuffersGeometry(surface, width, height, format) != 0) {
164         ctx->errorf("Failed to set buffer gemoetry");
165         return nullptr;
166     }
167     // TODO(b/332785161): if we know that surface can get destroyed dynamically while VM is running,
168     // consider calling ANativeWindow_acquire here and _release in destroy_android_surface, so that
169     // crosvm doesn't hold a dangling pointer.
170     return surface;
171 }
172 
destroy_android_surface(struct AndroidDisplayContext *,ANativeWindow *)173 extern "C" void destroy_android_surface(struct AndroidDisplayContext*, ANativeWindow*) {
174     // NOT IMPLEMENTED
175 }
176 
get_android_surface_buffer(struct AndroidDisplayContext * ctx,ANativeWindow * surface,ANativeWindow_Buffer * out_buffer)177 extern "C" bool get_android_surface_buffer(struct AndroidDisplayContext* ctx,
178                                            ANativeWindow* surface,
179                                            ANativeWindow_Buffer* out_buffer) {
180     if (out_buffer == nullptr) {
181         ctx->errorf("out_buffer is null");
182         return false;
183     }
184     if (ANativeWindow_lock(surface, out_buffer, nullptr) != 0) {
185         ctx->errorf("Failed to lock buffer");
186         return false;
187     }
188     return true;
189 }
190 
set_android_surface_position(struct AndroidDisplayContext * ctx,uint32_t x,uint32_t y)191 extern "C" void set_android_surface_position(struct AndroidDisplayContext* ctx, uint32_t x,
192                                              uint32_t y) {
193     if (ctx->disp_service == nullptr) {
194         ctx->errorf("Display service was not created");
195         return;
196     }
197     auto fd = ctx->disp_service->getCursorStream().get();
198     if (fd == -1) {
199         ctx->errorf("Invalid fd");
200         return;
201     }
202     uint32_t pos[] = {x, y};
203     write(fd, pos, sizeof(pos));
204 }
205 
post_android_surface_buffer(struct AndroidDisplayContext * ctx,ANativeWindow * surface)206 extern "C" void post_android_surface_buffer(struct AndroidDisplayContext* ctx,
207                                             ANativeWindow* surface) {
208     if (ANativeWindow_unlockAndPost(surface) != 0) {
209         ctx->errorf("Failed to unlock and post surface.");
210         return;
211     }
212 }
213