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
writeMetricsToBundle(JNIEnv * env,MediaAnalyticsItem * item,jobject mybundle)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 
writeAttributesToBundle(JNIEnv * env,jobject mybundle,char * buffer,size_t length)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