Dongwon Kang | bf98d54 | 2018-09-11 14:40:23 -0700 | [diff] [blame] | 1 | /* |
| 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 Essick | c535a55 | 2019-01-18 11:38:15 -0800 | [diff] [blame] | 17 | #define LOG_TAG "MediaMetricsJNI" |
| 18 | |
Dongwon Kang | bf98d54 | 2018-09-11 14:40:23 -0700 | [diff] [blame] | 19 | #include <jni.h> |
| 20 | #include <nativehelper/JNIHelp.h> |
| 21 | |
| 22 | #include "android_media_MediaMetricsJNI.h" |
| 23 | #include <media/MediaAnalyticsItem.h> |
| 24 | |
| 25 | |
Ray Essick | c535a55 | 2019-01-18 11:38:15 -0800 | [diff] [blame] | 26 | // This source file is compiled and linked into both: |
| 27 | // core/jni/ (libandroid_runtime.so) |
| 28 | // media/jni (libmedia2_jni.so) |
| 29 | |
Dongwon Kang | bf98d54 | 2018-09-11 14:40:23 -0700 | [diff] [blame] | 30 | namespace android { |
| 31 | |
| 32 | // place the attributes into a java PersistableBundle object |
| 33 | jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle) { |
| 34 | |
| 35 | jclass clazzBundle = env->FindClass("android/os/PersistableBundle"); |
| 36 | if (clazzBundle==NULL) { |
Ray Essick | c535a55 | 2019-01-18 11:38:15 -0800 | [diff] [blame] | 37 | ALOGE("can't find android/os/PersistableBundle"); |
Dongwon Kang | bf98d54 | 2018-09-11 14:40:23 -0700 | [diff] [blame] | 38 | return NULL; |
| 39 | } |
| 40 | // sometimes the caller provides one for us to fill |
| 41 | if (mybundle == NULL) { |
| 42 | // create the bundle |
| 43 | jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V"); |
| 44 | mybundle = env->NewObject(clazzBundle, constructID); |
| 45 | if (mybundle == NULL) { |
| 46 | return NULL; |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | // grab methods that we can invoke |
| 51 | jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"); |
| 52 | jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"); |
| 53 | jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"); |
| 54 | jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V"); |
| 55 | |
| 56 | // env, class, method, {parms} |
| 57 | //env->CallVoidMethod(env, mybundle, setIntID, jstr, jint); |
| 58 | |
| 59 | // iterate through my attributes |
| 60 | // -- get name, get type, get value |
| 61 | // -- insert appropriately into the bundle |
| 62 | for (size_t i = 0 ; i < item->mPropCount; i++ ) { |
| 63 | MediaAnalyticsItem::Prop *prop = &item->mProps[i]; |
| 64 | // build the key parameter from prop->mName |
| 65 | jstring keyName = env->NewStringUTF(prop->mName); |
| 66 | // invoke the appropriate method to insert |
| 67 | switch (prop->mType) { |
| 68 | case MediaAnalyticsItem::kTypeInt32: |
| 69 | env->CallVoidMethod(mybundle, setIntID, |
| 70 | keyName, (jint) prop->u.int32Value); |
| 71 | break; |
| 72 | case MediaAnalyticsItem::kTypeInt64: |
| 73 | env->CallVoidMethod(mybundle, setLongID, |
| 74 | keyName, (jlong) prop->u.int64Value); |
| 75 | break; |
| 76 | case MediaAnalyticsItem::kTypeDouble: |
| 77 | env->CallVoidMethod(mybundle, setDoubleID, |
| 78 | keyName, (jdouble) prop->u.doubleValue); |
| 79 | break; |
| 80 | case MediaAnalyticsItem::kTypeCString: |
| 81 | env->CallVoidMethod(mybundle, setStringID, keyName, |
| 82 | env->NewStringUTF(prop->u.CStringValue)); |
| 83 | break; |
| 84 | default: |
| 85 | ALOGE("to_String bad item type: %d for %s", |
| 86 | prop->mType, prop->mName); |
| 87 | break; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | return mybundle; |
| 92 | } |
| 93 | |
Ray Essick | c535a55 | 2019-01-18 11:38:15 -0800 | [diff] [blame] | 94 | // convert the specified batch metrics attributes to a persistent bundle. |
| 95 | // The encoding of the byte array is specified in |
| 96 | // frameworks/av/media/libmediametrics/MediaAnalyticsItem.cpp |
| 97 | // |
| 98 | // type encodings; matches frameworks/av/media/libmediametrics/MediaAnalyticsItem.cpp |
| 99 | enum { kInt32 = 0, kInt64, kDouble, kRate, kCString}; |
| 100 | |
| 101 | jobject MediaMetricsJNI::writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length) { |
| 102 | ALOGV("writeAttributes()"); |
| 103 | |
| 104 | if (buffer == NULL || length <= 0) { |
| 105 | ALOGW("bad parameters to writeAttributesToBundle()"); |
| 106 | return NULL; |
| 107 | } |
| 108 | |
| 109 | jclass clazzBundle = env->FindClass("android/os/PersistableBundle"); |
| 110 | if (clazzBundle==NULL) { |
| 111 | ALOGE("can't find android/os/PersistableBundle"); |
| 112 | return NULL; |
| 113 | } |
| 114 | // sometimes the caller provides one for us to fill |
| 115 | if (mybundle == NULL) { |
| 116 | // create the bundle |
| 117 | jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V"); |
| 118 | mybundle = env->NewObject(clazzBundle, constructID); |
| 119 | if (mybundle == NULL) { |
| 120 | ALOGD("unable to create mybundle"); |
| 121 | return NULL; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | int left = length; |
| 126 | char *buf = buffer; |
| 127 | |
| 128 | // grab methods that we can invoke |
| 129 | jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"); |
| 130 | jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"); |
| 131 | jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"); |
| 132 | jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V"); |
| 133 | |
| 134 | |
| 135 | #define _EXTRACT(size, val) \ |
| 136 | { if ((size) > left) goto badness; memcpy(&val, buf, (size)); buf += (size); left -= (size);} |
| 137 | #define _SKIP(size) \ |
| 138 | { if ((size) > left) goto badness; buf += (size); left -= (size);} |
| 139 | |
| 140 | int32_t bufsize; |
| 141 | _EXTRACT(sizeof(int32_t), bufsize); |
| 142 | if (bufsize != length) { |
| 143 | goto badness; |
| 144 | } |
| 145 | int32_t proto; |
| 146 | _EXTRACT(sizeof(int32_t), proto); |
| 147 | if (proto != 0) { |
| 148 | ALOGE("unsupported wire protocol %d", proto); |
| 149 | goto badness; |
| 150 | } |
| 151 | |
| 152 | int32_t count; |
| 153 | _EXTRACT(sizeof(int32_t), count); |
| 154 | |
| 155 | // iterate through my attributes |
| 156 | // -- get name, get type, get value, insert into bundle appropriately. |
| 157 | for (int i = 0 ; i < count; i++ ) { |
| 158 | // prop name len (int16) |
| 159 | int16_t keylen; |
| 160 | _EXTRACT(sizeof(int16_t), keylen); |
| 161 | if (keylen <= 0) goto badness; |
| 162 | // prop name itself |
| 163 | char *key = buf; |
| 164 | jstring keyName = env->NewStringUTF(buf); |
| 165 | _SKIP(keylen); |
| 166 | |
| 167 | // prop type (int8_t) |
| 168 | int8_t attrType; |
| 169 | _EXTRACT(sizeof(int8_t), attrType); |
| 170 | |
| 171 | int16_t attrSize; |
| 172 | _EXTRACT(sizeof(int16_t), attrSize); |
| 173 | |
| 174 | switch (attrType) { |
| 175 | case kInt32: |
| 176 | { |
| 177 | int32_t i32; |
| 178 | _EXTRACT(sizeof(int32_t), i32); |
| 179 | env->CallVoidMethod(mybundle, setIntID, |
| 180 | keyName, (jint) i32); |
| 181 | break; |
| 182 | } |
| 183 | case kInt64: |
| 184 | { |
| 185 | int64_t i64; |
| 186 | _EXTRACT(sizeof(int64_t), i64); |
| 187 | env->CallVoidMethod(mybundle, setLongID, |
| 188 | keyName, (jlong) i64); |
| 189 | break; |
| 190 | } |
| 191 | case kDouble: |
| 192 | { |
| 193 | double d64; |
| 194 | _EXTRACT(sizeof(double), d64); |
| 195 | env->CallVoidMethod(mybundle, setDoubleID, |
| 196 | keyName, (jdouble) d64); |
| 197 | break; |
| 198 | } |
| 199 | case kCString: |
| 200 | { |
| 201 | jstring value = env->NewStringUTF(buf); |
| 202 | env->CallVoidMethod(mybundle, setStringID, |
| 203 | keyName, value); |
| 204 | _SKIP(attrSize); |
| 205 | break; |
| 206 | } |
| 207 | default: |
| 208 | ALOGW("ignoring Attribute '%s' unknown type: %d", |
| 209 | key, attrType); |
| 210 | _SKIP(attrSize); |
| 211 | break; |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | // should have consumed it all |
| 216 | if (left != 0) { |
| 217 | ALOGW("did not consume entire buffer; left(%d) != 0", left); |
| 218 | goto badness; |
| 219 | } |
| 220 | |
| 221 | return mybundle; |
| 222 | |
| 223 | badness: |
| 224 | return NULL; |
| 225 | } |
| 226 | |
Dongwon Kang | bf98d54 | 2018-09-11 14:40:23 -0700 | [diff] [blame] | 227 | }; // namespace android |
| 228 | |