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 17 #define LOG_TAG "MediaMetricsJNI" 18 19 #include <jni.h> 20 #include <nativehelper/JNIHelp.h> 21 22 #include "android_media_MediaMetricsJNI.h" 23 #include <media/MediaAnalyticsItem.h> 24 25 26 // This source file is compiled and linked into both: 27 // core/jni/ (libandroid_runtime.so) 28 // media/jni (libmedia2_jni.so) 29 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) { 37 ALOGE("can't find android/os/PersistableBundle"); 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 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 227 }; // namespace android 228 229