blob: 494c61721e02f913912cbb858deafba48fd93a8e [file] [log] [blame]
Dongwon Kangbf98d542018-09-11 14:40:23 -07001/*
2 * Copyright 2017, 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
Ray Essickc535a552019-01-18 11:38:15 -080017#define LOG_TAG "MediaMetricsJNI"
18
Andy Hung73348482019-10-23 16:54:53 -070019#include <binder/Parcel.h>
Dongwon Kangbf98d542018-09-11 14:40:23 -070020#include <jni.h>
Ray Essick81fbc5b2019-12-07 06:24:59 -080021#include <media/MediaMetricsItem.h>
Dongwon Kangbf98d542018-09-11 14:40:23 -070022#include <nativehelper/JNIHelp.h>
23
24#include "android_media_MediaMetricsJNI.h"
Robert Shih4354a962019-11-10 12:09:08 -080025#include "android_os_Parcel.h"
Dongwon Kangbf98d542018-09-11 14:40:23 -070026
Marco Nelissena9a802f2019-09-24 09:27:22 -070027// This source file is compiled and linked into:
Ray Essickc535a552019-01-18 11:38:15 -080028// core/jni/ (libandroid_runtime.so)
Ray Essickc535a552019-01-18 11:38:15 -080029
Dongwon Kangbf98d542018-09-11 14:40:23 -070030namespace android {
31
Andy Hung73348482019-10-23 16:54:53 -070032namespace {
33struct BundleHelper {
34 BundleHelper(JNIEnv* _env, jobject _bundle)
35 : env(_env)
36 , clazzBundle(env->FindClass("android/os/PersistableBundle"))
37 , putIntID(env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"))
38 , putLongID(env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"))
39 , putDoubleID(env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"))
40 , putStringID(env->GetMethodID(clazzBundle,
41 "putString", "(Ljava/lang/String;Ljava/lang/String;)V"))
42 , constructID(env->GetMethodID(clazzBundle, "<init>", "()V"))
43 , bundle(_bundle == nullptr ? env->NewObject(clazzBundle, constructID) : _bundle)
44 { }
45
46 JNIEnv* const env;
47 const jclass clazzBundle;
48 const jmethodID putIntID;
49 const jmethodID putLongID;
50 const jmethodID putDoubleID;
51 const jmethodID putStringID;
52 const jmethodID constructID;
53 jobject const bundle;
54
Ray Essick81fbc5b2019-12-07 06:24:59 -080055 // We use templated put to access mediametrics::Item based on data type not type enum.
Andy Hung73348482019-10-23 16:54:53 -070056 // See std::variant and std::visit.
57 template<typename T>
58 void put(jstring keyName, const T& value) = delete;
59
60 template<>
61 void put(jstring keyName, const int32_t& value) {
62 env->CallVoidMethod(bundle, putIntID, keyName, (jint)value);
63 }
64
65 template<>
66 void put(jstring keyName, const int64_t& value) {
67 env->CallVoidMethod(bundle, putLongID, keyName, (jlong)value);
68 }
69
70 template<>
71 void put(jstring keyName, const double& value) {
72 env->CallVoidMethod(bundle, putDoubleID, keyName, (jdouble)value);
73 }
74
75 template<>
76 void put(jstring keyName, const char * const& value) {
77 env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
78 }
79
80 template<>
81 void put(jstring keyName, char * const& value) {
82 env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
83 }
84
85 template<>
86 void put(jstring keyName, const std::pair<int64_t, int64_t>& value) {
87 ; // rate is currently ignored
88 }
89
90 // We allow both jstring and non-jstring variants.
91 template<typename T>
92 void put(const char *keyName, const T& value) {
93 put(env->NewStringUTF(keyName), value);
94 }
95};
96} // namespace
97
Dongwon Kangbf98d542018-09-11 14:40:23 -070098// place the attributes into a java PersistableBundle object
Andy Hung73348482019-10-23 16:54:53 -070099jobject MediaMetricsJNI::writeMetricsToBundle(
Ray Essick81fbc5b2019-12-07 06:24:59 -0800100 JNIEnv* env, mediametrics::Item *item, jobject bundle)
Andy Hung73348482019-10-23 16:54:53 -0700101{
102 BundleHelper bh(env, bundle);
Dongwon Kangbf98d542018-09-11 14:40:23 -0700103
Andy Hung73348482019-10-23 16:54:53 -0700104 if (bh.bundle == nullptr) {
105 ALOGE("%s: unable to create Bundle", __func__);
106 return nullptr;
Dongwon Kangbf98d542018-09-11 14:40:23 -0700107 }
108
Andy Hung73348482019-10-23 16:54:53 -0700109 bh.put("__key", item->getKey().c_str());
110 if (item->getPid() != -1) {
111 bh.put("__pid", (int32_t)item->getPid());
Dongwon Kangbf98d542018-09-11 14:40:23 -0700112 }
Andy Hung73348482019-10-23 16:54:53 -0700113 if (item->getTimestamp() > 0) {
114 bh.put("__timestamp", (int64_t)item->getTimestamp());
Ray Essickc535a552019-01-18 11:38:15 -0800115 }
Andy Hung73348482019-10-23 16:54:53 -0700116 if (item->getUid() != -1) {
117 bh.put("__uid", (int32_t)item->getUid());
Ray Essickc535a552019-01-18 11:38:15 -0800118 }
Andy Hung73348482019-10-23 16:54:53 -0700119 for (const auto &prop : *item) {
120 const char *name = prop.getName();
121 if (name == nullptr) continue;
122 prop.visit([&] (auto &value) { bh.put(name, value); });
Ray Essickc535a552019-01-18 11:38:15 -0800123 }
Andy Hung73348482019-10-23 16:54:53 -0700124 return bh.bundle;
Ray Essickc535a552019-01-18 11:38:15 -0800125}
126
Robert Shih4354a962019-11-10 12:09:08 -0800127// Helper function to convert a native PersistableBundle to a Java
128// PersistableBundle.
129jobject MediaMetricsJNI::nativeToJavaPersistableBundle(JNIEnv *env,
130 os::PersistableBundle* nativeBundle) {
131 if (env == NULL || nativeBundle == NULL) {
132 ALOGE("Unexpected NULL parmeter");
133 return NULL;
134 }
135
136 // Create a Java parcel with the native parcel data.
137 // Then create a new PersistableBundle with that parcel as a parameter.
138 jobject jParcel = android::createJavaParcelObject(env);
139 if (jParcel == NULL) {
140 ALOGE("Failed to create a Java Parcel.");
141 return NULL;
142 }
143
144 android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
145 if (nativeParcel == NULL) {
146 ALOGE("Failed to get the native Parcel.");
147 return NULL;
148 }
149
150 android::status_t result = nativeBundle->writeToParcel(nativeParcel);
151 nativeParcel->setDataPosition(0);
152 if (result != android::OK) {
153 ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
154 return NULL;
155 }
156
157#define STATIC_INIT_JNI(T, obj, method, globalref, ...) \
158 static T obj{};\
159 if (obj == NULL) { \
160 obj = method(__VA_ARGS__); \
161 if (obj == NULL) { \
162 ALOGE("%s can't find " #obj, __func__); \
163 return NULL; \
164 } else { \
165 obj = globalref; \
166 }\
167 } \
168
169 STATIC_INIT_JNI(jclass, clazzBundle, env->FindClass,
170 static_cast<jclass>(env->NewGlobalRef(clazzBundle)),
171 "android/os/PersistableBundle");
172 STATIC_INIT_JNI(jfieldID, bundleCreatorId, env->GetStaticFieldID,
173 bundleCreatorId,
174 clazzBundle, "CREATOR", "Landroid/os/Parcelable$Creator;");
175 STATIC_INIT_JNI(jobject, bundleCreator, env->GetStaticObjectField,
176 env->NewGlobalRef(bundleCreator),
177 clazzBundle, bundleCreatorId);
178 STATIC_INIT_JNI(jclass, clazzCreator, env->FindClass,
179 static_cast<jclass>(env->NewGlobalRef(clazzCreator)),
180 "android/os/Parcelable$Creator");
181 STATIC_INIT_JNI(jmethodID, createFromParcelId, env->GetMethodID,
182 createFromParcelId,
183 clazzCreator, "createFromParcel", "(Landroid/os/Parcel;)Ljava/lang/Object;");
184
185 jobject newBundle = env->CallObjectMethod(bundleCreator, createFromParcelId, jParcel);
186 if (newBundle == NULL) {
187 ALOGE("Failed to create a new PersistableBundle "
188 "from the createFromParcel call.");
189 }
190
191 return newBundle;
192}
193
Dongwon Kangbf98d542018-09-11 14:40:23 -0700194}; // namespace android
195