1/*
2 * Copyright (C) 2016 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#undef LOG_TAG
18#define LOG_TAG "MediaAnalyticsItem"
19
20#include <inttypes.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/types.h>
24
25#include <binder/Parcel.h>
26#include <utils/Errors.h>
27#include <utils/Log.h>
28#include <utils/Mutex.h>
29#include <utils/SortedVector.h>
30#include <utils/threads.h>
31
32#include <media/stagefright/foundation/AString.h>
33
34#include <binder/IServiceManager.h>
35#include <media/IMediaAnalyticsService.h>
36#include <media/MediaAnalyticsItem.h>
37#include <private/android_filesystem_config.h>
38
39namespace android {
40
41#define DEBUG_SERVICEACCESS     0
42#define DEBUG_API               0
43#define DEBUG_ALLOCATIONS       0
44
45// after this many failed attempts, we stop trying [from this process] and just say that
46// the service is off.
47#define SVC_TRIES               2
48
49// the few universal keys we have
50const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny  = "any";
51const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone  = "none";
52
53const char * const MediaAnalyticsItem::EnabledProperty  = "media.metrics.enabled";
54const char * const MediaAnalyticsItem::EnabledPropertyPersist  = "persist.media.metrics.enabled";
55const int MediaAnalyticsItem::EnabledProperty_default  = 1;
56
57
58// access functions for the class
59MediaAnalyticsItem::MediaAnalyticsItem()
60    : mPid(-1),
61      mUid(-1),
62      mSessionID(MediaAnalyticsItem::SessionIDNone),
63      mTimestamp(0),
64      mFinalized(0),
65      mPropCount(0), mPropSize(0), mProps(NULL)
66{
67    mKey = MediaAnalyticsItem::kKeyNone;
68}
69
70MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
71    : mPid(-1),
72      mUid(-1),
73      mSessionID(MediaAnalyticsItem::SessionIDNone),
74      mTimestamp(0),
75      mFinalized(0),
76      mPropCount(0), mPropSize(0), mProps(NULL)
77{
78    if (DEBUG_ALLOCATIONS) {
79        ALOGD("Allocate MediaAnalyticsItem @ %p", this);
80    }
81    mKey = key;
82}
83
84MediaAnalyticsItem::~MediaAnalyticsItem() {
85    if (DEBUG_ALLOCATIONS) {
86        ALOGD("Destroy  MediaAnalyticsItem @ %p", this);
87    }
88    clear();
89}
90
91void MediaAnalyticsItem::clear() {
92
93    // clean allocated storage from key
94    mKey.clear();
95
96    // clean various major parameters
97    mSessionID = MediaAnalyticsItem::SessionIDNone;
98
99    // clean attributes
100    // contents of the attributes
101    for (size_t i = 0 ; i < mPropSize; i++ ) {
102        clearProp(&mProps[i]);
103    }
104    // the attribute records themselves
105    if (mProps != NULL) {
106        free(mProps);
107        mProps = NULL;
108    }
109    mPropSize = 0;
110    mPropCount = 0;
111
112    return;
113}
114
115// make a deep copy of myself
116MediaAnalyticsItem *MediaAnalyticsItem::dup() {
117    MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
118
119    if (dst != NULL) {
120        // key as part of constructor
121        dst->mPid = this->mPid;
122        dst->mUid = this->mUid;
123        dst->mSessionID = this->mSessionID;
124        dst->mTimestamp = this->mTimestamp;
125        dst->mFinalized = this->mFinalized;
126
127        // properties aka attributes
128        dst->growProps(this->mPropCount);
129        for(size_t i=0;i<mPropCount;i++) {
130            copyProp(&dst->mProps[i], &this->mProps[i]);
131        }
132        dst->mPropCount = this->mPropCount;
133    }
134
135    return dst;
136}
137
138// so clients can send intermediate values to be overlaid later
139MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
140    mFinalized = value;
141    return *this;
142}
143
144bool MediaAnalyticsItem::getFinalized() const {
145    return mFinalized;
146}
147
148MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
149    mSessionID = id;
150    return *this;
151}
152
153MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
154    return mSessionID;
155}
156
157MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
158
159    if (mSessionID == SessionIDNone) {
160        // get one from the server
161        MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
162        sp<IMediaAnalyticsService> svc = getInstance();
163        if (svc != NULL) {
164            newid = svc->generateUniqueSessionID();
165        }
166        mSessionID = newid;
167    }
168
169    return mSessionID;
170}
171
172MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
173    mSessionID = MediaAnalyticsItem::SessionIDNone;
174    return *this;
175}
176
177MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
178    mTimestamp = ts;
179    return *this;
180}
181
182nsecs_t MediaAnalyticsItem::getTimestamp() const {
183    return mTimestamp;
184}
185
186MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
187    mPid = pid;
188    return *this;
189}
190
191pid_t MediaAnalyticsItem::getPid() const {
192    return mPid;
193}
194
195MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
196    mUid = uid;
197    return *this;
198}
199
200uid_t MediaAnalyticsItem::getUid() const {
201    return mUid;
202}
203
204// this key is for the overall record -- "codec", "player", "drm", etc
205MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
206    mKey = key;
207    return *this;
208}
209
210MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
211    return mKey;
212}
213
214// number of attributes we have in this record
215int32_t MediaAnalyticsItem::count() const {
216    return mPropCount;
217}
218
219// find the proper entry in the list
220size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
221{
222    size_t i = 0;
223    for (; i < mPropCount; i++) {
224        Prop *prop = &mProps[i];
225        if (prop->mNameLen != len) {
226            continue;
227        }
228        if (memcmp(name, prop->mName, len) == 0) {
229            break;
230        }
231    }
232    return i;
233}
234
235MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
236    size_t len = strlen(name);
237    size_t i = findPropIndex(name, len);
238    if (i < mPropCount) {
239        return &mProps[i];
240    }
241    return NULL;
242}
243
244void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
245    mNameLen = len;
246    mName = (const char *) malloc(len+1);
247    memcpy ((void *)mName, name, len+1);
248}
249
250// used only as part of a storing operation
251MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
252    size_t len = strlen(name);
253    size_t i = findPropIndex(name, len);
254    Prop *prop;
255
256    if (i < mPropCount) {
257        prop = &mProps[i];
258    } else {
259        if (i == mPropSize) {
260            growProps();
261            // XXX: verify success
262        }
263        i = mPropCount++;
264        prop = &mProps[i];
265        prop->setName(name, len);
266    }
267
268    return prop;
269}
270
271// set the values
272void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
273    Prop *prop = allocateProp(name);
274    prop->mType = kTypeInt32;
275    prop->u.int32Value = value;
276}
277
278void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
279    Prop *prop = allocateProp(name);
280    prop->mType = kTypeInt64;
281    prop->u.int64Value = value;
282}
283
284void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
285    Prop *prop = allocateProp(name);
286    prop->mType = kTypeDouble;
287    prop->u.doubleValue = value;
288}
289
290void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
291
292    Prop *prop = allocateProp(name);
293    // any old value will be gone
294    prop->mType = kTypeCString;
295    prop->u.CStringValue = strdup(value);
296}
297
298void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
299    Prop *prop = allocateProp(name);
300    prop->mType = kTypeRate;
301    prop->u.rate.count = count;
302    prop->u.rate.duration = duration;
303}
304
305
306// find/add/set fused into a single operation
307void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
308    Prop *prop = allocateProp(name);
309    switch (prop->mType) {
310        case kTypeInt32:
311            prop->u.int32Value += value;
312            break;
313        default:
314            clearPropValue(prop);
315            prop->mType = kTypeInt32;
316            prop->u.int32Value = value;
317            break;
318    }
319}
320
321void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
322    Prop *prop = allocateProp(name);
323    switch (prop->mType) {
324        case kTypeInt64:
325            prop->u.int64Value += value;
326            break;
327        default:
328            clearPropValue(prop);
329            prop->mType = kTypeInt64;
330            prop->u.int64Value = value;
331            break;
332    }
333}
334
335void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
336    Prop *prop = allocateProp(name);
337    switch (prop->mType) {
338        case kTypeRate:
339            prop->u.rate.count += count;
340            prop->u.rate.duration += duration;
341            break;
342        default:
343            clearPropValue(prop);
344            prop->mType = kTypeRate;
345            prop->u.rate.count = count;
346            prop->u.rate.duration = duration;
347            break;
348    }
349}
350
351void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
352    Prop *prop = allocateProp(name);
353    switch (prop->mType) {
354        case kTypeDouble:
355            prop->u.doubleValue += value;
356            break;
357        default:
358            clearPropValue(prop);
359            prop->mType = kTypeDouble;
360            prop->u.doubleValue = value;
361            break;
362    }
363}
364
365// find & extract values
366bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
367    Prop *prop = findProp(name);
368    if (prop == NULL || prop->mType != kTypeInt32) {
369        return false;
370    }
371    if (value != NULL) {
372        *value = prop->u.int32Value;
373    }
374    return true;
375}
376
377bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
378    Prop *prop = findProp(name);
379    if (prop == NULL || prop->mType != kTypeInt64) {
380        return false;
381    }
382    if (value != NULL) {
383        *value = prop->u.int64Value;
384    }
385    return true;
386}
387
388bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
389    Prop *prop = findProp(name);
390    if (prop == NULL || prop->mType != kTypeRate) {
391        return false;
392    }
393    if (count != NULL) {
394        *count = prop->u.rate.count;
395    }
396    if (duration != NULL) {
397        *duration = prop->u.rate.duration;
398    }
399    if (rate != NULL) {
400        double r = 0.0;
401        if (prop->u.rate.duration != 0) {
402            r = prop->u.rate.count / (double) prop->u.rate.duration;
403        }
404        *rate = r;
405    }
406    return true;
407}
408
409bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
410    Prop *prop = findProp(name);
411    if (prop == NULL || prop->mType != kTypeDouble) {
412        return false;
413    }
414    if (value != NULL) {
415        *value = prop->u.doubleValue;
416    }
417    return true;
418}
419
420// caller responsible for the returned string
421bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
422    Prop *prop = findProp(name);
423    if (prop == NULL || prop->mType != kTypeDouble) {
424        return false;
425    }
426    if (value != NULL) {
427        *value = strdup(prop->u.CStringValue);
428    }
429    return true;
430}
431
432// remove indicated keys and their values
433// return value is # keys removed
434int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
435    int zapped = 0;
436    if (attrs == NULL || n <= 0) {
437        return -1;
438    }
439    for (ssize_t i = 0 ; i < n ;  i++) {
440        const char *name = attrs[i];
441        size_t len = strlen(name);
442        size_t j = findPropIndex(name, len);
443        if (j >= mPropCount) {
444            // not there
445            continue;
446        } else if (j+1 == mPropCount) {
447            // last one, shorten
448            zapped++;
449            clearProp(&mProps[j]);
450            mPropCount--;
451        } else {
452            // in the middle, bring last one down and shorten
453            zapped++;
454            clearProp(&mProps[j]);
455            mProps[j] = mProps[mPropCount-1];
456            mPropCount--;
457        }
458    }
459    return zapped;
460}
461
462// remove any keys NOT in the provided list
463// return value is # keys removed
464int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
465    int zapped = 0;
466    if (attrs == NULL || n <= 0) {
467        return -1;
468    }
469    for (ssize_t i = mPropCount-1 ; i >=0 ;  i--) {
470        Prop *prop = &mProps[i];
471        for (ssize_t j = 0; j < n ; j++) {
472            if (strcmp(prop->mName, attrs[j]) == 0) {
473                clearProp(prop);
474                zapped++;
475                if (i != (ssize_t)(mPropCount-1)) {
476                    *prop = mProps[mPropCount-1];
477                }
478                initProp(&mProps[mPropCount-1]);
479                mPropCount--;
480                break;
481            }
482        }
483    }
484    return zapped;
485}
486
487// remove a single key
488// return value is 0 (not found) or 1 (found and removed)
489int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
490    return filter(1, &name);
491}
492
493// handle individual items/properties stored within the class
494//
495
496void MediaAnalyticsItem::initProp(Prop *prop) {
497    if (prop != NULL) {
498        prop->mName = NULL;
499        prop->mNameLen = 0;
500
501        prop->mType = kTypeNone;
502    }
503}
504
505void MediaAnalyticsItem::clearProp(Prop *prop)
506{
507    if (prop != NULL) {
508        if (prop->mName != NULL) {
509            free((void *)prop->mName);
510            prop->mName = NULL;
511            prop->mNameLen = 0;
512        }
513
514        clearPropValue(prop);
515    }
516}
517
518void MediaAnalyticsItem::clearPropValue(Prop *prop)
519{
520    if (prop != NULL) {
521        if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
522            free(prop->u.CStringValue);
523            prop->u.CStringValue = NULL;
524        }
525        prop->mType = kTypeNone;
526    }
527}
528
529void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
530{
531    // get rid of any pointers in the dst
532    clearProp(dst);
533
534    *dst = *src;
535
536    // fix any pointers that we blindly copied, so we have our own copies
537    if (dst->mName) {
538        void *p =  malloc(dst->mNameLen + 1);
539        memcpy (p, src->mName, dst->mNameLen + 1);
540        dst->mName = (const char *) p;
541    }
542    if (dst->mType == kTypeCString) {
543        dst->u.CStringValue = strdup(src->u.CStringValue);
544    }
545}
546
547void MediaAnalyticsItem::growProps(int increment)
548{
549    if (increment <= 0) {
550        increment = kGrowProps;
551    }
552    int nsize = mPropSize + increment;
553    Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
554
555    if (ni != NULL) {
556        for (int i = mPropSize; i < nsize; i++) {
557            initProp(&ni[i]);
558        }
559        mProps = ni;
560        mPropSize = nsize;
561    }
562}
563
564// Parcel / serialize things for binder calls
565//
566
567int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
568    // into 'this' object
569    // .. we make a copy of the string to put away.
570    mKey = data.readCString();
571    mSessionID = data.readInt64();
572    mFinalized = data.readInt32();
573    mTimestamp = data.readInt64();
574
575    int count = data.readInt32();
576    for (int i = 0; i < count ; i++) {
577            MediaAnalyticsItem::Attr attr = data.readCString();
578            int32_t ztype = data.readInt32();
579                switch (ztype) {
580                    case MediaAnalyticsItem::kTypeInt32:
581                            setInt32(attr, data.readInt32());
582                            break;
583                    case MediaAnalyticsItem::kTypeInt64:
584                            setInt64(attr, data.readInt64());
585                            break;
586                    case MediaAnalyticsItem::kTypeDouble:
587                            setDouble(attr, data.readDouble());
588                            break;
589                    case MediaAnalyticsItem::kTypeCString:
590                            setCString(attr, data.readCString());
591                            break;
592                    case MediaAnalyticsItem::kTypeRate:
593                            {
594                                int64_t count = data.readInt64();
595                                int64_t duration = data.readInt64();
596                                setRate(attr, count, duration);
597                            }
598                            break;
599                    default:
600                            ALOGE("reading bad item type: %d, idx %d",
601                                  ztype, i);
602                            return -1;
603                }
604    }
605
606    return 0;
607}
608
609int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
610    if (data == NULL) return -1;
611
612
613    data->writeCString(mKey.c_str());
614    data->writeInt64(mSessionID);
615    data->writeInt32(mFinalized);
616    data->writeInt64(mTimestamp);
617
618    // set of items
619    int count = mPropCount;
620    data->writeInt32(count);
621    for (int i = 0 ; i < count; i++ ) {
622            Prop *prop = &mProps[i];
623            data->writeCString(prop->mName);
624            data->writeInt32(prop->mType);
625            switch (prop->mType) {
626                case MediaAnalyticsItem::kTypeInt32:
627                        data->writeInt32(prop->u.int32Value);
628                        break;
629                case MediaAnalyticsItem::kTypeInt64:
630                        data->writeInt64(prop->u.int64Value);
631                        break;
632                case MediaAnalyticsItem::kTypeDouble:
633                        data->writeDouble(prop->u.doubleValue);
634                        break;
635                case MediaAnalyticsItem::kTypeRate:
636                        data->writeInt64(prop->u.rate.count);
637                        data->writeInt64(prop->u.rate.duration);
638                        break;
639                case MediaAnalyticsItem::kTypeCString:
640                        data->writeCString(prop->u.CStringValue);
641                        break;
642                default:
643                        ALOGE("found bad Prop type: %d, idx %d, name %s",
644                              prop->mType, i, prop->mName);
645                        break;
646            }
647    }
648
649    return 0;
650}
651
652
653AString MediaAnalyticsItem::toString() {
654
655    AString result = "(";
656    char buffer[512];
657
658    // same order as we spill into the parcel, although not required
659    // key+session are our primary matching criteria
660    //RBE ALOGD("mKey.c_str");
661    result.append(mKey.c_str());
662    //RBE ALOGD("post-mKey.c_str");
663    result.append(":");
664    snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
665    result.append(buffer);
666
667    // we need these internally, but don't want to upload them
668    snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid);
669    result.append(buffer);
670
671    snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
672    result.append(buffer);
673    snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
674    result.append(buffer);
675
676    // set of items
677    int count = mPropCount;
678    snprintf(buffer, sizeof(buffer), "%d:", count);
679    result.append(buffer);
680    for (int i = 0 ; i < count; i++ ) {
681            Prop *prop = &mProps[i];
682            switch (prop->mType) {
683                case MediaAnalyticsItem::kTypeInt32:
684                        snprintf(buffer,sizeof(buffer),
685                        "%s=%d:", prop->mName, prop->u.int32Value);
686                        break;
687                case MediaAnalyticsItem::kTypeInt64:
688                        snprintf(buffer,sizeof(buffer),
689                        "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
690                        break;
691                case MediaAnalyticsItem::kTypeDouble:
692                        snprintf(buffer,sizeof(buffer),
693                        "%s=%e:", prop->mName, prop->u.doubleValue);
694                        break;
695                case MediaAnalyticsItem::kTypeRate:
696                        snprintf(buffer,sizeof(buffer),
697                        "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
698                        prop->u.rate.count, prop->u.rate.duration);
699                        break;
700                case MediaAnalyticsItem::kTypeCString:
701                        snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
702                        result.append(buffer);
703                        // XXX: sanitize string for ':' '='
704                        result.append(prop->u.CStringValue);
705                        buffer[0] = ':';
706                        buffer[1] = '\0';
707                        break;
708                default:
709                        ALOGE("to_String bad item type: %d for %s",
710                              prop->mType, prop->mName);
711                        break;
712            }
713            result.append(buffer);
714    }
715
716    result.append(")");
717
718    return result;
719}
720
721// for the lazy, we offer methods that finds the service and
722// calls the appropriate daemon
723bool MediaAnalyticsItem::selfrecord() {
724    return selfrecord(false);
725}
726
727bool MediaAnalyticsItem::selfrecord(bool forcenew) {
728
729    if (DEBUG_API) {
730        AString p = this->toString();
731        ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
732    }
733
734    sp<IMediaAnalyticsService> svc = getInstance();
735
736    if (svc != NULL) {
737        svc->submit(this, forcenew);
738        return true;
739    } else {
740        AString p = this->toString();
741        ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
742        return false;
743    }
744}
745
746// get a connection we can reuse for most of our lifetime
747// static
748sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
749static Mutex sInitMutex;
750
751//static
752bool MediaAnalyticsItem::isEnabled() {
753    int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
754
755    if (enabled == -1) {
756        enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
757    }
758    if (enabled == -1) {
759        enabled = MediaAnalyticsItem::EnabledProperty_default;
760    }
761    if (enabled <= 0) {
762        return false;
763    }
764    return true;
765}
766
767//static
768sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
769    static const char *servicename = "media.metrics";
770    static int tries_remaining = SVC_TRIES;
771    int enabled = isEnabled();
772
773    if (enabled == false) {
774        if (DEBUG_SERVICEACCESS) {
775                ALOGD("disabled");
776        }
777        return NULL;
778    }
779
780    // completely skip logging from certain UIDs. We do this here
781    // to avoid the multi-second timeouts while we learn that
782    // sepolicy will not let us find the service.
783    // We do this only for a select set of UIDs
784    // The sepolicy protection is still in place, we just want a faster
785    // response from this specific, small set of uids.
786    {
787        uid_t uid = getuid();
788        switch (uid) {
789            case AID_RADIO:     // telephony subsystem, RIL
790                return NULL;
791                break;
792            default:
793                // let sepolicy deny access if appropriate
794                break;
795        }
796    }
797
798    {
799        Mutex::Autolock _l(sInitMutex);
800        const char *badness = "";
801
802        // think of tries_remaining as telling us whether service==NULL because
803        // (1) we haven't tried to initialize it yet
804        // (2) we've tried to initialize it, but failed.
805        if (sAnalyticsService == NULL && tries_remaining > 0) {
806            sp<IServiceManager> sm = defaultServiceManager();
807            if (sm != NULL) {
808                sp<IBinder> binder = sm->getService(String16(servicename));
809                if (binder != NULL) {
810                    sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
811                } else {
812                    badness = "did not find service";
813                }
814            } else {
815                badness = "No Service Manager access";
816            }
817
818            if (sAnalyticsService == NULL) {
819                if (tries_remaining > 0) {
820                    tries_remaining--;
821                }
822                if (DEBUG_SERVICEACCESS) {
823                    ALOGD("Unable to bind to service %s: %s", servicename, badness);
824                }
825            }
826        }
827
828        return sAnalyticsService;
829    }
830}
831
832
833// merge the info from 'incoming' into this record.
834// we finish with a union of this+incoming and special handling for collisions
835bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
836
837    // if I don't have key or session id, take them from incoming
838    // 'this' should never be missing both of them...
839    if (mKey.empty()) {
840        mKey = incoming->mKey;
841    } else if (mSessionID == 0) {
842        mSessionID = incoming->mSessionID;
843    }
844
845    // we always take the more recent 'finalized' value
846    setFinalized(incoming->getFinalized());
847
848    // for each attribute from 'incoming', resolve appropriately
849    int nattr = incoming->mPropCount;
850    for (int i = 0 ; i < nattr; i++ ) {
851        Prop *iprop = &incoming->mProps[i];
852        Prop *oprop = findProp(iprop->mName);
853        const char *p = iprop->mName;
854        size_t len = strlen(p);
855        char semantic = p[len-1];
856
857        if (oprop == NULL) {
858            // no oprop, so we insert the new one
859            oprop = allocateProp(p);
860            copyProp(oprop, iprop);
861        } else {
862            // merge iprop into oprop
863            switch (semantic) {
864                case '<':       // first  aka keep old)
865                    /* nop */
866                    break;
867
868                default:        // default is 'last'
869                case '>':       // last (aka keep new)
870                    copyProp(oprop, iprop);
871                    break;
872
873                case '+':       /* sum */
874                    // XXX validate numeric types, sum in place
875                    break;
876
877            }
878        }
879    }
880
881    // not sure when we'd return false...
882    return true;
883}
884
885} // namespace android
886
887