1 /*
2  * Copyright (C) 2023 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 <dlfcn.h>
18 
19 #include <media/NdkImageReader.h>
20 #include <media/NdkMediaCodec.h>
21 #include <media/NdkMediaDataSource.h>
22 #include <media/NdkMediaDrm.h>
23 
24 #include "berberis/base/logging.h"
25 #include "berberis/guest_abi/function_wrappers.h"
26 #include "berberis/guest_abi/guest_params.h"
27 #include "berberis/proxy_loader/proxy_library_builder.h"
28 
29 namespace berberis {
30 
31 namespace {
32 
33 // media_status_t AImageReader_setBufferRemovedListener(
34 //         AImageReader* reader, AImageReader_BufferRemovedListener* listener);
DoCustomTrampoline_AImageReader_setBufferRemovedListener(HostCode,ProcessState * state)35 void DoCustomTrampoline_AImageReader_setBufferRemovedListener(HostCode /* callee */,
36                                                               ProcessState* state) {
37   // The documentation says that "Note that calling this method will replace previously
38   // registered listeners."
39   static AImageReader_BufferRemovedListener host_listener;
40   auto [reader, listener] =
41       GuestParamsValues<decltype(AImageReader_setBufferRemovedListener)>(state);
42   if (listener != nullptr) {
43     host_listener.context = listener->context;
44     // typedef void (*AImageReader_BufferRemovedCallback)(void* context,
45     //                                                    AImageReader* reader,
46     //                                                    AHardwareBuffer* buffer);
47     host_listener.onBufferRemoved = WrapGuestFunction(
48         GuestType(listener->onBufferRemoved), "AImageReader_setBufferRemovedListener-callback");
49     listener = &host_listener;
50   }
51 
52   auto&& [ret] = GuestReturnReference<decltype(AImageReader_setBufferRemovedListener)>(state);
53   ret = AImageReader_setBufferRemovedListener(reader, listener);
54 }
55 
56 // media_status_t AImageReader_setImageListener(
57 //         AImageReader* reader, AImageReader_ImageListener* listener);
DoCustomTrampoline_AImageReader_setImageListener(HostCode,ProcessState * state)58 void DoCustomTrampoline_AImageReader_setImageListener(HostCode /* callee */, ProcessState* state) {
59   // The documentation says that "Note that calling this method will replace previously
60   // registered listeners."
61   static AImageReader_ImageListener host_listener;
62   auto [reader, listener] = GuestParamsValues<decltype(AImageReader_setImageListener)>(state);
63   if (listener != nullptr) {
64     host_listener.context = listener->context;
65 
66     // typedef void(* AImageReader_ImageCallback) (void *context, AImageReader *reader)
67     host_listener.onImageAvailable = WrapGuestFunction(GuestType(listener->onImageAvailable),
68                                                        "AImageReader_setImageListener-callback");
69     listener = &host_listener;
70   }
71 
72   auto&& [ret] = GuestReturnReference<decltype(AImageReader_setImageListener)>(state);
73   ret = AImageReader_setImageListener(reader, listener);
74 }
75 
76 // typedef void (*AMediaCodecOnAsyncInputAvailable)(AMediaCodec* codec,
77 //                                                  void *userdata,
78 //                                                  int32_t index);
79 //
80 // typedef void (*AMediaCodecOnAsyncOutputAvailable)(AMediaCodec* codec,
81 //                                                   void *userdata,
82 //                                                   int32_t index,
83 //                                                   AMediaCodecBufferInfo* bufferInfo);
84 //
85 // typedef void (*AMediaCodecOnAsyncFormatChanged)(AMediaCodec* codec,
86 //                                                 void *userdata,
87 //                                                 AMediaFormat* format);
88 //
89 // typedef void (*AMediaCodecOnAsyncError)(AMediaCodec* codec,
90 //                                         void *userdata,
91 //                                         media_status_t error,
92 //                                         int32_t actionCode,
93 //                                         const char *detail);
94 //
95 //
96 // struct AMediaCodecOnAsyncNotifyCallback {
97 //   AMediaCodecOnAsyncInputAvailable  onAsyncInputAvailable;
98 //   AMediaCodecOnAsyncOutputAvailable onAsyncOutputAvailable;
99 //   AMediaCodecOnAsyncFormatChanged   onAsyncFormatChanged;
100 //   AMediaCodecOnAsyncError           onAsyncError;
101 // };
102 //
103 // media_status_t AMediaCodec_setAsyncNotifyCallback(AMediaCodec*,
104 //                                                   AMediaCodecOnAsyncNotifyCallback callback,
105 //                                                   void *userdata);
106 #if defined(NATIVE_BRIDGE_GUEST_ARCH_ARM)
107 // Note: passing struct (not pointer) as a parameter is quite complicated.
108 // And currently not supported by GuestParams on ARM.
109 //
110 // There AMediaCodecOnAsyncNotifyCallback struct argument is cut in two parts - first three
111 // pointers are passed in r1, r2, r3 and fourth pointer is passed on stack.  To handle that
112 // case correctly we need to know how structure is organized internally (e.g. floating point
113 // arguments would go to VFP registers if aapcs-vfp is used).
114 //
115 // Treat four pointers as four arguments till GuestParams could handle that case on ARM.
DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode,ProcessState * state)116 void DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode /* callee */,
117                                                            ProcessState* state) {
118   using PFN_callback = media_status_t (*)(AMediaCodec*,
119                                           AMediaCodecOnAsyncInputAvailable,
120                                           AMediaCodecOnAsyncOutputAvailable,
121                                           AMediaCodecOnAsyncFormatChanged,
122                                           AMediaCodecOnAsyncError,
123                                           void*);
124   auto [codec,
125         guest_cb_onAsyncInputAvailable,
126         guest_cb_onAsyncOutputAvailable,
127         guest_cb_onAsyncFormatChanged,
128         guest_cb_onAsyncError,
129         userdata] = GuestParamsValues<PFN_callback>(state);
130 
131   AMediaCodecOnAsyncNotifyCallback host_cb;
132   host_cb.onAsyncInputAvailable = WrapGuestFunction(guest_cb_onAsyncInputAvailable,
133                                                     "AMediaCodecOnAsyncInputAvailable-callback");
134   host_cb.onAsyncOutputAvailable = WrapGuestFunction(guest_cb_onAsyncOutputAvailable,
135                                                      "AMediaCodecOnAsyncOutputAvailable-callback");
136   host_cb.onAsyncFormatChanged =
137       WrapGuestFunction(guest_cb_onAsyncFormatChanged, "AMediaCodecOnAsyncFormatChanged-callback");
138   host_cb.onAsyncError =
139       WrapGuestFunction(guest_cb_onAsyncError, "AMediaCodecOnAsyncError-callback");
140 
141   auto&& [ret] = GuestReturnReference<PFN_callback>(state);
142   ret = AMediaCodec_setAsyncNotifyCallback(codec, host_cb, userdata);
143 }
144 
145 #else /* defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) */
146 
DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode,ProcessState * state)147 void DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode /* callee */,
148                                                            ProcessState* state) {
149   auto [codec, cb, userdata] =
150       GuestParamsValues<decltype(AMediaCodec_setAsyncNotifyCallback)>(state);
151 
152   AMediaCodecOnAsyncNotifyCallback host_cb;
153   host_cb.onAsyncInputAvailable = WrapGuestFunction(
154       GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncInputAvailable),
155       "AMediaCodecOnAsyncInputAvailable-callback");
156   host_cb.onAsyncOutputAvailable = WrapGuestFunction(
157       GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncOutputAvailable),
158       "AMediaCodecOnAsyncOutputAvailable-callback");
159   host_cb.onAsyncFormatChanged = WrapGuestFunction(
160       GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncFormatChanged),
161       "AMediaCodecOnAsyncFormatChanged-callback");
162   host_cb.onAsyncError =
163       WrapGuestFunction(GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncError),
164                         "AMediaCodecOnAsyncError-callback");
165 
166   auto&& [ret] = GuestReturnReference<decltype(AMediaCodec_setAsyncNotifyCallback)>(state);
167   ret = AMediaCodec_setAsyncNotifyCallback(codec, host_cb, userdata);
168 }
169 
170 #endif /* defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) */
171 
172 // typedef void (*AMediaDataSourceClose)(void *userdata);
173 // void AMediaDataSource_setClose(AMediaDataSource*, AMediaDataSourceClose);
DoCustomTrampoline_AMediaDataSource_setClose(HostCode,ProcessState * state)174 void DoCustomTrampoline_AMediaDataSource_setClose(HostCode /* callee */, ProcessState* state) {
175   auto [datasource, guest_callback] = GuestParamsValues<decltype(AMediaDataSource_setClose)>(state);
176   AMediaDataSourceClose host_callback =
177       WrapGuestFunction(guest_callback, "AMediaDataSource_setClose-callback");
178   AMediaDataSource_setClose(datasource, host_callback);
179 }
180 
181 // typedef ssize_t (*AMediaDataSourceGetSize)(void *userdata);
182 // void AMediaDataSource_setGetSize(AMediaDataSource*, AMediaDataSourceGetSize);
DoCustomTrampoline_AMediaDataSource_setGetSize(HostCode,ProcessState * state)183 void DoCustomTrampoline_AMediaDataSource_setGetSize(HostCode /* callee */, ProcessState* state) {
184   auto [datasource, guest_callback] =
185       GuestParamsValues<decltype(AMediaDataSource_setGetSize)>(state);
186   AMediaDataSourceGetSize host_callback =
187       WrapGuestFunction(guest_callback, "AMediaDataSource_setGetSize-callback");
188   AMediaDataSource_setGetSize(datasource, host_callback);
189 }
190 
191 // typedef ssize_t (*AMediaDataSourceReadAt)(
192 //    void *userdata, off64_t offset, void * buffer, size_t size);
193 // void AMediaDataSource_setReadAt(AMediaDataSource*, AMediaDataSourceReadAt);
DoCustomTrampoline_AMediaDataSource_setReadAt(HostCode,ProcessState * state)194 void DoCustomTrampoline_AMediaDataSource_setReadAt(HostCode /* callee */, ProcessState* state) {
195   auto [datasource, guest_callback] =
196       GuestParamsValues<decltype(AMediaDataSource_setReadAt)>(state);
197   AMediaDataSourceReadAt host_callback =
198       WrapGuestFunction(guest_callback, "AMediaDataSource_setReadAt-callback");
199   AMediaDataSource_setReadAt(datasource, host_callback);
200 }
201 
202 #if defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) && defined(__i386__)
203 
204 #include "trampolines_arm_to_x86-inl.h"  // generated file NOLINT [build/include]
205 
206 #elif defined(NATIVE_BRIDGE_GUEST_ARCH_ARM64) && defined(__x86_64__)
207 
208 #include "trampolines_arm64_to_x86_64-inl.h"  // generated file NOLINT [build/include]
209 
210 #elif defined(NATIVE_BRIDGE_GUEST_ARCH_RISCV64) && defined(__x86_64__)
211 
212 #include "trampolines_riscv64_to_x86_64-inl.h"  // generated file NOLINT [build/include]
213 
214 #else
215 
216 #error "Unknown guest/host arch combination"
217 
218 #endif
219 
220 DEFINE_INIT_PROXY_LIBRARY("libmediandk.so")
221 
222 }  // namespace
223 
224 }  // namespace berberis
225