@ -100,9 +100,6 @@ MediaAnalyticsService::MediaAnalyticsService()
mDumpProtoDefault ( MediaAnalyticsItem : : PROTO_V1 ) {
ALOGD ( " MediaAnalyticsService created " ) ;
// clear our queues
mOpen = new List < MediaAnalyticsItem * > ( ) ;
mFinalized = new List < MediaAnalyticsItem * > ( ) ;
mItemsSubmitted = 0 ;
mItemsFinalized = 0 ;
@ -118,26 +115,13 @@ MediaAnalyticsService::MediaAnalyticsService()
MediaAnalyticsService : : ~ MediaAnalyticsService ( ) {
ALOGD ( " MediaAnalyticsService destroyed " ) ;
// clean out mOpen and mFinalized
while ( mOpen - > size ( ) > 0 ) {
MediaAnalyticsItem * oitem = * ( mOpen - > begin ( ) ) ;
mOpen - > erase ( mOpen - > begin ( ) ) ;
while ( mItems . size ( ) > 0 ) {
MediaAnalyticsItem * oitem = * ( mItems . begin ( ) ) ;
mItems . erase ( mItems . begin ( ) ) ;
delete oitem ;
mItemsDiscarded + + ;
mItemsDiscardedCount + + ;
}
delete mOpen ;
mOpen = NULL ;
while ( mFinalized - > size ( ) > 0 ) {
MediaAnalyticsItem * oitem = * ( mFinalized - > begin ( ) ) ;
mFinalized - > erase ( mFinalized - > begin ( ) ) ;
delete oitem ;
mItemsDiscarded + + ;
mItemsDiscardedCount + + ;
}
delete mFinalized ;
mFinalized = NULL ;
}
@ -149,9 +133,14 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID()
}
// caller surrenders ownership of 'item'
MediaAnalyticsItem : : SessionID_t MediaAnalyticsService : : submit ( MediaAnalyticsItem * item , bool forcenew ) {
MediaAnalyticsItem : : SessionID_t MediaAnalyticsService : : submit ( MediaAnalyticsItem * item , bool forcenew )
{
UNUSED ( forcenew ) ;
MediaAnalyticsItem : : SessionID_t id = MediaAnalyticsItem : : SessionIDInvalid ;
// fill in a sessionID if we do not yet have one
if ( item - > getSessionID ( ) < = MediaAnalyticsItem : : SessionIDNone ) {
item - > setSessionID ( generateUniqueSessionID ( ) ) ;
}
// we control these, generally not trusting user input
nsecs_t now = systemTime ( SYSTEM_TIME_REALTIME ) ;
@ -164,9 +153,7 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
int uid_given = item - > getUid ( ) ;
int pid_given = item - > getPid ( ) ;
// although we do make exceptions for particular client uids
// that we know we trust.
//
// although we do make exceptions for some trusted client uids
bool isTrusted = false ;
ALOGV ( " caller has uid=%d, embedded uid=%d " , uid , uid_given ) ;
@ -192,7 +179,6 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
break ;
}
// Overwrite package name and version if the caller was untrusted.
if ( ! isTrusted ) {
setPkgInfo ( item , item - > getUid ( ) , true , true ) ;
@ -217,75 +203,23 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
return MediaAnalyticsItem : : SessionIDInvalid ;
}
// if we have a sesisonid in the new record, look to make
// XXX: if we have a sessionid in the new record, look to make
// sure it doesn't appear in the finalized list.
// XXX: this is for security / DOS prevention.
// may also require that we persist the unique sessionIDs
// across boots [instead of within a single boot]
// match this new record up against records in the open
// list...
// if there's a match, merge them together
// deal with moving the old / merged record into the finalized que
bool finalizing = item - > getFinalized ( ) ;
Mutex : : Autolock _l ( mLock ) ;
// if finalizing, we'll remove it
MediaAnalyticsItem * oitem = findItem ( mOpen , item , finalizing | forcenew ) ;
if ( oitem ! = NULL ) {
if ( forcenew ) {
// old one gets finalized, then we insert the new one
// so we'll have 2 records at the end of this.
// but don't finalize an empty record
if ( oitem - > count ( ) = = 0 ) {
// we're responsible for disposing of the dead record
delete oitem ;
oitem = NULL ;
} else {
oitem - > setFinalized ( true ) ;
saveItem ( mFinalized , oitem , 0 ) ;
}
// new record could itself be marked finalized...
id = item - > getSessionID ( ) ;
if ( finalizing ) {
saveItem ( mFinalized , item , 0 ) ;
mItemsFinalized + + ;
} else {
saveItem ( mOpen , item , 1 ) ;
}
} else {
// combine the records, send it to finalized if appropriate
oitem - > merge ( item ) ;
id = oitem - > getSessionID ( ) ;
if ( finalizing ) {
saveItem ( mFinalized , oitem , 0 ) ;
mItemsFinalized + + ;
}
// we're responsible for disposing of the dead record
delete item ;
item = NULL ;
}
} else {
// nothing to merge, save the new record
id = item - > getSessionID ( ) ;
if ( finalizing ) {
if ( item - > count ( ) = = 0 ) {
// drop empty records
delete item ;
item = NULL ;
} else {
saveItem ( mFinalized , item , 0 ) ;
mItemsFinalized + + ;
}
} else {
saveItem ( mOpen , item , 1 ) ;
}
if ( item - > count ( ) = = 0 ) {
// drop empty records
delete item ;
item = NULL ;
return MediaAnalyticsItem : : SessionIDInvalid ;
}
// save the new record
MediaAnalyticsItem : : SessionID_t id = item - > getSessionID ( ) ;
saveItem ( item ) ;
mItemsFinalized + + ;
return id ;
}
@ -378,6 +312,7 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
}
Mutex : : Autolock _l ( mLock ) ;
// mutex between insertion and dumping the contents
mDumpProto = chosenProto ;
@ -392,9 +327,9 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
if ( clear ) {
// remove everything from the finalized queue
while ( m Finalized- > size ( ) > 0 ) {
MediaAnalyticsItem * oitem = * ( m Finalized- > begin ( ) ) ;
m Finalized- > erase ( mFinalized - > begin ( ) ) ;
while ( m Items. size ( ) > 0 ) {
MediaAnalyticsItem * oitem = * ( m Items. begin ( ) ) ;
m Items. erase ( mItems . begin ( ) ) ;
delete oitem ;
mItemsDiscarded + + ;
}
@ -408,7 +343,8 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
}
// dump headers
void MediaAnalyticsService : : dumpHeaders ( String8 & result , nsecs_t ts_since ) {
void MediaAnalyticsService : : dumpHeaders ( String8 & result , nsecs_t ts_since )
{
const size_t SIZE = 512 ;
char buffer [ SIZE ] ;
@ -425,7 +361,7 @@ void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
snprintf ( buffer , SIZE ,
" Since Boot: Submissions: %8 " PRId64
" Finalizations : %8" PRId64 " \n " ,
" Accepted : %8" PRId64 " \n " ,
mItemsSubmitted , mItemsFinalized ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE ,
@ -433,19 +369,17 @@ void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
" (by Count: % " PRId64 " by Expiration: % " PRId64 " ) \n " ,
mItemsDiscarded , mItemsDiscardedCount , mItemsDiscardedExpire ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE ,
" Summary Sets Discarded: % " PRId64 " \n " , mSetsDiscarded ) ;
result . append ( buffer ) ;
if ( ts_since ! = 0 ) {
snprintf ( buffer , SIZE ,
" Dump ing Queue entries more recent than: %" PRId64 " \n " ,
" Emitting Queue entries more recent than: % " PRId64 " \n " ,
( int64_t ) ts_since ) ;
result . append ( buffer ) ;
}
}
// the recent, detailed queues
void MediaAnalyticsService : : dumpRecent ( String8 & result , nsecs_t ts_since , const char * only ) {
void MediaAnalyticsService : : dumpRecent ( String8 & result , nsecs_t ts_since , const char * only )
{
const size_t SIZE = 512 ;
char buffer [ SIZE ] ;
@ -456,30 +390,27 @@ void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const
// show the recently recorded records
snprintf ( buffer , sizeof ( buffer ) , " \n Finalized Metrics (oldest first): \n " ) ;
result . append ( buffer ) ;
result . append ( this - > dumpQueue ( mFinalized , ts_since , only ) ) ;
snprintf ( buffer , sizeof ( buffer ) , " \n In-Progress Metrics (newest first): \n " ) ;
result . append ( buffer ) ;
result . append ( this - > dumpQueue ( mOpen , ts_since , only ) ) ;
result . append ( this - > dumpQueue ( ts_since , only ) ) ;
// show who is connected and injecting records?
// talk about # records fed to the 'readers'
// talk about # records we discarded, perhaps "discarded w/o reading" too
}
// caller has locked mLock...
String8 MediaAnalyticsService : : dumpQueue ( List < MediaAnalyticsItem * > * theList ) {
return dumpQueue ( theList , ( nsecs_t ) 0 , NULL ) ;
String8 MediaAnalyticsService : : dumpQueue ( ) {
return dumpQueue ( ( nsecs_t ) 0 , NULL ) ;
}
String8 MediaAnalyticsService : : dumpQueue ( List< MediaAnalyticsItem * > * theList , nsecs_t ts_since , const char * only ) {
String8 MediaAnalyticsService : : dumpQueue ( nsecs_t ts_since , const char * only ) {
String8 result ;
int slot = 0 ;
if ( theList- > empty ( ) ) {
if ( mItems. empty ( ) ) {
result . append ( " empty \n " ) ;
} else {
List < MediaAnalyticsItem * > : : iterator it = theList- > begin ( ) ;
for ( ; it ! = theList- > end ( ) ; it + + ) {
List < MediaAnalyticsItem * > : : iterator it = mItems. begin ( ) ;
for ( ; it ! = mItems. end ( ) ; it + + ) {
nsecs_t when = ( * it ) - > getTimestamp ( ) ;
if ( when < ts_since ) {
continue ;
@ -500,35 +431,25 @@ String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, ns
//
// Our Cheap in-core, non-persistent records management.
// XXX: rewrite this to manage persistence, etc.
// insert appropriately into queue
// caller should hold mLock
void MediaAnalyticsService : : saveItem ( List < MediaAnalyticsItem * > * l , MediaAnalyticsItem * item , int front ) {
if ( front ) {
// for non-finalized stuff, since we expect to reference it again soon,
// make it quicker to find (nearer the front of our list)
l - > push_front ( item ) ;
} else {
// for finalized records, which we want to dump 'in sequence order'
l - > push_back ( item ) ;
}
void MediaAnalyticsService : : saveItem ( MediaAnalyticsItem * item )
{
// our reclaim process is for oldest-first queues
if ( front ) {
return ;
}
Mutex : : Autolock _l ( mLock ) ;
// mutex between insertion and dumping the contents
// we want to dump 'in FIFO order', so insert at the end
mItems . push_back ( item ) ;
// keep removing old records the front until we're in-bounds (count)
if ( mMaxRecords > 0 ) {
while ( l- > size ( ) > ( size_t ) mMaxRecords ) {
MediaAnalyticsItem * oitem = * ( l- > begin ( ) ) ;
while ( mItems. size ( ) > ( size_t ) mMaxRecords ) {
MediaAnalyticsItem * oitem = * ( mItems. begin ( ) ) ;
if ( oitem = = item ) {
break ;
}
l- > erase ( l - > begin ( ) ) ;
mItems. erase ( mItems . begin ( ) ) ;
delete oitem ;
mItemsDiscarded + + ;
mItemsDiscardedCount + + ;
@ -536,10 +457,11 @@ void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyti
}
// keep removing old records the front until we're in-bounds (count)
// NB: expired entries aren't removed until the next insertion, which could be a while
if ( mMaxRecordAgeNs > 0 ) {
nsecs_t now = systemTime ( SYSTEM_TIME_REALTIME ) ;
while ( l- > size ( ) > 0 ) {
MediaAnalyticsItem * oitem = * ( l- > begin ( ) ) ;
while ( mItems. size ( ) > 0 ) {
MediaAnalyticsItem * oitem = * ( mItems. begin ( ) ) ;
nsecs_t when = oitem - > getTimestamp ( ) ;
if ( oitem = = item ) {
break ;
@ -549,7 +471,7 @@ void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyti
// this (and the rest) are recent enough to keep
break ;
}
l- > erase ( l - > begin ( ) ) ;
mItems. erase ( mItems . begin ( ) ) ;
delete oitem ;
mItemsDiscarded + + ;
mItemsDiscardedExpire + + ;
@ -557,79 +479,6 @@ void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyti
}
}
// are they alike enough that nitem can be folded into oitem?
static bool compatibleItems ( MediaAnalyticsItem * oitem , MediaAnalyticsItem * nitem ) {
// general safety
if ( nitem - > getUid ( ) ! = oitem - > getUid ( ) ) {
return false ;
}
if ( nitem - > getPid ( ) ! = oitem - > getPid ( ) ) {
return false ;
}
// key -- needs to match
if ( nitem - > getKey ( ) = = oitem - > getKey ( ) ) {
// still in the game.
} else {
return false ;
}
// session id -- empty field in new is allowed
MediaAnalyticsItem : : SessionID_t osession = oitem - > getSessionID ( ) ;
MediaAnalyticsItem : : SessionID_t nsession = nitem - > getSessionID ( ) ;
if ( nsession ! = osession ) {
// incoming '0' matches value in osession
if ( nsession ! = 0 ) {
return false ;
}
}
return true ;
}
// find the incomplete record that this will overlay
// caller should hold mLock
MediaAnalyticsItem * MediaAnalyticsService : : findItem ( List < MediaAnalyticsItem * > * theList , MediaAnalyticsItem * nitem , bool removeit ) {
if ( nitem = = NULL ) {
return NULL ;
}
MediaAnalyticsItem * item = NULL ;
for ( List < MediaAnalyticsItem * > : : iterator it = theList - > begin ( ) ;
it ! = theList - > end ( ) ; it + + ) {
MediaAnalyticsItem * tmp = ( * it ) ;
if ( ! compatibleItems ( tmp , nitem ) ) {
continue ;
}
// we match! this is the one I want.
if ( removeit ) {
theList - > erase ( it ) ;
}
item = tmp ;
break ;
}
return item ;
}
// delete the indicated record
// caller should hold mLock
void MediaAnalyticsService : : deleteItem ( List < MediaAnalyticsItem * > * l , MediaAnalyticsItem * item ) {
for ( List < MediaAnalyticsItem * > : : iterator it = l - > begin ( ) ;
it ! = l - > end ( ) ; it + + ) {
if ( ( * it ) - > getSessionID ( ) ! = item - > getSessionID ( ) )
continue ;
delete * it ;
l - > erase ( it ) ;
break ;
}
}
static std : : string allowedKeys [ ] =
{
" audiorecord " ,
@ -676,7 +525,9 @@ bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
# define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
// give me the package name, perhaps going to find it
void MediaAnalyticsService : : setPkgInfo ( MediaAnalyticsItem * item , uid_t uid , bool setName , bool setVersion ) {
// manages its own mutex operations internally
void MediaAnalyticsService : : setPkgInfo ( MediaAnalyticsItem * item , uid_t uid , bool setName , bool setVersion )
{
ALOGV ( " asking for packagename to go with uid=%d " , uid ) ;
if ( ! setName & & ! setVersion ) {
@ -686,22 +537,26 @@ void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool
nsecs_t now = systemTime ( SYSTEM_TIME_REALTIME ) ;
struct UidToPkgMap mapping ;
mapping . uid = ( - 1 ) ;
ssize_t i = mPkgMappings . indexOfKey ( uid ) ;
if ( i > = 0 ) {
mapping = mPkgMappings . valueAt ( i ) ;
ALOGV ( " Expiration? uid %d expiration % " PRId64 " now % " PRId64 ,
uid , mapping . expiration , now ) ;
if ( mapping . expiration < now ) {
// purge our current entry and re-query
ALOGV ( " entry for uid %d expired, now= % " PRId64 " " , uid , now ) ;
mPkgMappings . removeItemsAt ( i , 1 ) ;
// could cheat and use a goto back to the top of the routine.
// a good compiler should recognize the local tail recursion...
return setPkgInfo ( item , uid , setName , setVersion ) ;
mapping . uid = ( uid_t ) ( - 1 ) ;
{
Mutex : : Autolock _l ( mLock_mappings ) ;
int i = mPkgMappings . indexOfKey ( uid ) ;
if ( i > = 0 ) {
mapping = mPkgMappings . valueAt ( i ) ;
ALOGV ( " Expiration? uid %d expiration % " PRId64 " now % " PRId64 ,
uid , mapping . expiration , now ) ;
if ( mapping . expiration < = now ) {
// purge the stale entry and fall into re-fetching
ALOGV ( " entry for uid %d expired, now= % " PRId64 " " , uid , now ) ;
mPkgMappings . removeItemsAt ( i ) ;
mapping . uid = ( uid_t ) ( - 1 ) ;
}
}
} else {
}
// if we did not find it
if ( mapping . uid = = ( uid_t ) ( - 1 ) ) {
std : : string pkg ;
std : : string installer = " " ;
int64_t versionCode = 0 ;
@ -711,7 +566,7 @@ void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool
pkg = pw - > pw_name ;
}
// find the proper value -- should we cache this binder??
// find the proper value
sp < IBinder > binder = NULL ;
sp < IServiceManager > sm = defaultServiceManager ( ) ;