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