1 /*
2  * Copyright (C) 2021 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 #define LOG_TAG "AidlConversion"
18 
19 #include <sstream>
20 #include <type_traits>
21 
22 #include <android_os_Parcel.h>
23 #include <binder/Parcel.h>
24 #include <jni.h>
25 #include <log/log.h>
26 #include <media/AidlConversion.h>
27 #include <system/audio.h>
28 
29 #include "core_jni_helpers.h"
30 
31 namespace {
32 
33 using namespace android;
34 using media::audio::common::AudioChannelLayout;
35 using media::audio::common::AudioEncapsulationMode;
36 using media::audio::common::AudioFormatDescription;
37 using media::audio::common::AudioStreamType;
38 using media::audio::common::AudioUsage;
39 
40 #define PACKAGE "android/media/audio/common"
41 #define CLASSNAME PACKAGE "/AidlConversion"
42 
43 // Used for creating messages.
44 template <typename T>
45 struct type_info {
46     static constexpr const char* name = "";
47 };
48 #define TYPE_NAME_QUOTE(x) #x
49 #define TYPE_NAME_STRINGIFY(x) TYPE_NAME_QUOTE(x)
50 #define TYPE_NAME(n)                                                \
51     template <>                                                     \
52     struct type_info<n> {                                           \
53         static constexpr const char* name = TYPE_NAME_STRINGIFY(n); \
54     }
55 
56 TYPE_NAME(AudioChannelLayout);
57 TYPE_NAME(AudioEncapsulationMode);
58 TYPE_NAME(AudioFormatDescription);
59 TYPE_NAME(AudioStreamType);
60 TYPE_NAME(AudioUsage);
61 TYPE_NAME(audio_encapsulation_mode_t);
62 TYPE_NAME(audio_stream_type_t);
63 TYPE_NAME(audio_usage_t);
64 
65 template <typename AidlType, typename LegacyType, typename ConvFunc>
aidl2legacy(JNIEnv * env,AidlType aidl,const ConvFunc & conv,LegacyType fallbackValue)66 int aidl2legacy(JNIEnv* env, AidlType aidl, const ConvFunc& conv, LegacyType fallbackValue) {
67     const auto result = conv(aidl);
68     if (result.ok()) {
69         return result.value();
70     }
71     std::ostringstream msg;
72     msg << "Failed to convert " << type_info<AidlType>::name << " value "
73         << static_cast<std::underlying_type_t<AidlType>>(aidl);
74     jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
75     return fallbackValue;
76 }
77 
78 template <typename LegacyType, typename AidlType, typename ConvFunc>
legacy2aidl(JNIEnv * env,LegacyType legacy,const ConvFunc & conv,AidlType fallbackValue)79 int legacy2aidl(JNIEnv* env, LegacyType legacy, const ConvFunc& conv, AidlType fallbackValue) {
80     const auto result = conv(legacy);
81     if (result.ok()) {
82         return static_cast<std::underlying_type_t<AidlType>>(result.value());
83     }
84     std::ostringstream msg;
85     msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
86     jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
87     return static_cast<std::underlying_type_t<AidlType>>(fallbackValue);
88 }
89 
90 template <typename AidlType, typename ConvFunc>
aidlParcel2legacy(JNIEnv * env,jobject jParcel,const ConvFunc & conv,int fallbackValue)91 int aidlParcel2legacy(JNIEnv* env, jobject jParcel, const ConvFunc& conv, int fallbackValue) {
92     if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
93         AidlType aidl{};
94         if (status_t status = aidl.readFromParcel(parcel); status == OK) {
95             auto legacy = conv(aidl);
96             if (legacy.ok()) {
97                 return legacy.value();
98             }
99         } else {
100             ALOGE("aidl2legacy: Failed to read from parcel: %s", statusToString(status).c_str());
101         }
102         std::ostringstream msg;
103         msg << "Failed to convert " << type_info<AidlType>::name << " value " << aidl.toString();
104         jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
105     } else {
106         ALOGE("aidl2legacy: Failed to retrieve the native parcel from Java parcel");
107     }
108     return fallbackValue;
109 }
110 
111 template <typename LegacyType, typename ConvFunc>
legacy2aidlParcel(JNIEnv * env,LegacyType legacy,const ConvFunc & conv)112 jobject legacy2aidlParcel(JNIEnv* env, LegacyType legacy, const ConvFunc& conv) {
113     auto aidl = conv(legacy);
114     if (!aidl.ok()) {
115         std::ostringstream msg;
116         msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
117         jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
118         return 0;
119     }
120     if (jobject jParcel = createJavaParcelObject(env); jParcel != 0) {
121         if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
122             if (status_t status = aidl.value().writeToParcel(parcel); status == OK) {
123                 parcel->setDataPosition(0);
124                 return jParcel;
125             } else {
126                 ALOGE("legacy2aidl: Failed to write to parcel: %s, aidl value: %s",
127                       statusToString(status).c_str(), aidl.value().toString().c_str());
128             }
129         } else {
130             ALOGE("legacy2aidl: Failed to retrieve the native parcel from Java parcel");
131         }
132         env->DeleteLocalRef(jParcel);
133     } else {
134         ALOGE("legacy2aidl: Failed to create Java parcel");
135     }
136     return 0;
137 }
138 
aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(JNIEnv * env,jobject,jobject jParcel,jboolean isInput)139 int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(JNIEnv* env, jobject,
140                                                                jobject jParcel, jboolean isInput) {
141     return aidlParcel2legacy<AudioChannelLayout>(
142             env, jParcel,
143             [isInput](const AudioChannelLayout& l) {
144                 return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
145             },
146             AUDIO_CHANNEL_INVALID);
147 }
148 
legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(JNIEnv * env,jobject,int legacy,jboolean isInput)149 jobject legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
150         JNIEnv* env, jobject, int /*audio_channel_mask_t*/ legacy, jboolean isInput) {
151     return legacy2aidlParcel(
152             env, static_cast<audio_channel_mask_t>(legacy), [isInput](audio_channel_mask_t m) {
153                 return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
154             });
155 }
156 
aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(JNIEnv * env,jobject,jobject jParcel)157 int aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(JNIEnv* env, jobject,
158                                                              jobject jParcel) {
159     return aidlParcel2legacy<
160             AudioFormatDescription>(env, jParcel, aidl2legacy_AudioFormatDescription_audio_format_t,
161                                     AUDIO_FORMAT_INVALID);
162 }
163 
legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(JNIEnv * env,jobject,int legacy)164 jobject legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(JNIEnv* env, jobject,
165                                                                  int /*audio_format_t*/ legacy) {
166     return legacy2aidlParcel(env, static_cast<audio_format_t>(legacy),
167                              legacy2aidl_audio_format_t_AudioFormatDescription);
168 }
169 
aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(JNIEnv * env,jobject,jint aidl)170 jint aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(JNIEnv* env, jobject,
171                                                                    jint aidl) {
172     return aidl2legacy(env, AudioEncapsulationMode(static_cast<int32_t>(aidl)),
173                        android::aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t,
174                        AUDIO_ENCAPSULATION_MODE_NONE);
175 }
176 
legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(JNIEnv * env,jobject,jint legacy)177 jint legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(JNIEnv* env, jobject,
178                                                                    jint legacy) {
179     return legacy2aidl(env, static_cast<audio_encapsulation_mode_t>(legacy),
180                        android::legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode,
181                        AudioEncapsulationMode::INVALID);
182 }
183 
aidl2legacy_AudioStreamType_audio_stream_type_t(JNIEnv * env,jobject,jint aidl)184 jint aidl2legacy_AudioStreamType_audio_stream_type_t(JNIEnv* env, jobject, jint aidl) {
185     return aidl2legacy(env, AudioStreamType(static_cast<int32_t>(aidl)),
186                        android::aidl2legacy_AudioStreamType_audio_stream_type_t,
187                        AUDIO_STREAM_DEFAULT);
188 }
189 
legacy2aidl_audio_stream_type_t_AudioStreamType(JNIEnv * env,jobject,jint legacy)190 jint legacy2aidl_audio_stream_type_t_AudioStreamType(JNIEnv* env, jobject, jint legacy) {
191     return legacy2aidl(env, static_cast<audio_stream_type_t>(legacy),
192                        android::legacy2aidl_audio_stream_type_t_AudioStreamType,
193                        AudioStreamType::INVALID);
194 }
195 
aidl2legacy_AudioUsage_audio_usage_t(JNIEnv * env,jobject,jint aidl)196 jint aidl2legacy_AudioUsage_audio_usage_t(JNIEnv* env, jobject, jint aidl) {
197     return aidl2legacy(env, AudioUsage(static_cast<int32_t>(aidl)),
198                        android::aidl2legacy_AudioUsage_audio_usage_t, AUDIO_USAGE_UNKNOWN);
199 }
200 
legacy2aidl_audio_usage_t_AudioUsage(JNIEnv * env,jobject,jint legacy)201 jint legacy2aidl_audio_usage_t_AudioUsage(JNIEnv* env, jobject, jint legacy) {
202     return legacy2aidl(env, static_cast<audio_usage_t>(legacy),
203                        android::legacy2aidl_audio_usage_t_AudioUsage, AudioUsage::INVALID);
204 }
205 
206 const JNINativeMethod gMethods[] = {
207         {"aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t", "(Landroid/os/Parcel;Z)I",
208          reinterpret_cast<void*>(aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t)},
209         {"legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel", "(IZ)Landroid/os/Parcel;",
210          reinterpret_cast<void*>(legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel)},
211         {"aidl2legacy_AudioFormatDescription_Parcel_audio_format_t", "(Landroid/os/Parcel;)I",
212          reinterpret_cast<void*>(aidl2legacy_AudioFormatDescription_Parcel_audio_format_t)},
213         {"legacy2aidl_audio_format_t_AudioFormatDescription_Parcel", "(I)Landroid/os/Parcel;",
214          reinterpret_cast<void*>(legacy2aidl_audio_format_t_AudioFormatDescription_Parcel)},
215         {"aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t", "(I)I",
216          reinterpret_cast<void*>(aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t)},
217         {"legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode", "(I)I",
218          reinterpret_cast<void*>(legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode)},
219         {"aidl2legacy_AudioStreamType_audio_stream_type_t", "(I)I",
220          reinterpret_cast<void*>(aidl2legacy_AudioStreamType_audio_stream_type_t)},
221         {"legacy2aidl_audio_stream_type_t_AudioStreamType", "(I)I",
222          reinterpret_cast<void*>(legacy2aidl_audio_stream_type_t_AudioStreamType)},
223         {"aidl2legacy_AudioUsage_audio_usage_t", "(I)I",
224          reinterpret_cast<void*>(aidl2legacy_AudioUsage_audio_usage_t)},
225         {"legacy2aidl_audio_usage_t_AudioUsage", "(I)I",
226          reinterpret_cast<void*>(legacy2aidl_audio_usage_t_AudioUsage)},
227 };
228 
229 } // namespace
230 
register_android_media_audio_common_AidlConversion(JNIEnv * env)231 int register_android_media_audio_common_AidlConversion(JNIEnv* env) {
232     return RegisterMethodsOrDie(env, CLASSNAME, gMethods, NELEM(gMethods));
233 }
234