7
header
log entry
log entry
/log/batch message
Fig. 6: Structure of messages sent to play.googleapis.com/
log/batch by the Google Play Services Clearcut logger. Each
message consists of one or more bundles of log entries,
indicated in brown. Each bundle has a header containing
device details and persistent identifiers (Google androidID,
NID cookie) and specifying the log source. This header is
followed by one or more log entries, the format of the log
entries being determined by the log source.
CARRIER_SERVICES, ANDROID_DIALER, ONEGOOGLE_MOBILE, GOOGLE_NOW_LAUNCHER,
DRIVE, COPRESENCE_NO_IDS, AUTOFILL_WITH_GOOGLE, SCOOBY_EVENT,
SCOOBY_EVENT_LOG, BEACON_GCORE, NETREC, BRELLA, GOOGLE_HELP, PHOTOS,
CALENDAR, CALENDAR_UNIFIED_SYNC, BUSINESS_VOICE, IDENTITY_FRONTEND,
GMS_CORE_PEOPLE, LATIN_IME, DL_FONTS, CAR, ICING, ACTIVITY_RECOGNITION,
ANDROID_CONTACTS, ANDROID_GROWTH, ANDROID_GSA, CLIENT_LOGGING_PROD,
GOOGLETTS, CAST_SENDER_SDK, ANDROID_VERIFY_APPS, ANDROID_BACKUP,
ANDROID_MESSAGING, ANDROID_OTA, ANDROID_GMAIL, ANDROID_SNET_GCORE,
GAL_PROVIDER, GLAS, TACHYON_LOG_REQUEST, CLEARCUT_FUNNEL, CLEARCUT_LOG_LOSS,
DIALER_ANDROID_PRIMES, CARRIER_SERVICES_ANDROID_PRIMES, TURBO_ANDROID_PRIMES,
PHOTOS_ANDROID_PRIMES, ANDROID_MESSAGING_PRIMES, GOOGLETTS_ANDROID_PRIMES,
SETTINGS_INTELLIGENCE_ANDROID_PRIMES, ANDROID_GSA_ANDROID_PRIMES,
SAFETYHUB_ANDROID_PRIMES, WIFI_ASSISTANT_PRIMES, DRIVE_ANDROID_PRIMES,
GMAIL_ANDROID_PRIMES, STREAMZ_ANDROID_GROWTH, STREAMZ_ANDROID_GSA,
STREAMZ_ONEGOOGLE_ANDROID, STREAMZ_HERREVAD, STREAMZ_CALENDAR,
STREAMZ_PHOTOS_ANDROID, STREAMZ_ANDROID_AUTH_ACCOUNT, STREAMZ_GELLER,
STREAMZ_NGA, BUGLE_COUNTERS, PSEUDONYMOUS_ID_COUNTERS, GMAIL_COUNTERS,
WESTWORLD_COUNTERS, GOOGLE_KEYBOARD_COUNTERS, ANDROID_CONTACTS_COUNTERS,
WALLPAPER_PICKER_COUNTERS, PLATFORM_STATS_COUNTERS
[
TABLE I: Log source names observed in Google
Play Services Clearcut logger messages sent to
play.googleapis.com/log/batch (taken from [3]). The log
sources studied here are highlighted in red.
Messages app contains more than 2000 distinct protobufs
15
.)
and then (iii) trace back within the code to determine how the
value of each entry in the protobuf is calculated. Figure 7(b)
shows the result of this fairly laborious process.
It can be seen that many of the numerical values within
the message encode event and state information, for ex-
15
The protobufs themselves are encoded within the app in
compact protobuf format, which is undocumented although there
are useful comments embedded in the Android source code, see
https://cs.android.com/android/platform/superproject/+/master:external/
protobuf/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
logEntry:{
1: 1635013045967
6 {
1: 2
3 {
1: 1
2: 1
<...>
5 {
1: 1635013045028
2: 898
}
8: 2
9: 1282237833693804524
12: 1
14: 2
16: 2
17: 4
18: 10
19: 4
20 {
1: 30524580
3: ""
}
21: 778
27: 8480061162880308485
31: "NOT_AVAILABLE"
33: "-8443536869600326524"
34: "5478611868067030819"
<...>
(a)
logEntry:{
timestamp: 1635013045967
event {
eventType: BUGLE_MESSAGE
bugleMessage {
messageProtocol: ONE_ON_ONE
bugleMessageStatus: SENT
<...>
messageTiming {
currentTime_ms: 1635013045028
elapsedTimeSinceMsgSendRecv_ms: 898
}
bugleMessageSource: CONVERSATION_ACTIVITY
usageStatsLoggingId: 12822378336938045248
conversationType: ONE_ON_ONE
sendAttempt: FIRST_ATTEMPT_TO_SEND
wasRCS: HAS_ALWAYS_BEEN_XMS_CONVERSATION
rcsStatus: RCS_AVAILABILITIES_ISSUES
configStatus: CARRIER_SETUP_PENDING
phoneNumberFormat2: PHONENUMBER
carrierServicesData {
versionCode: 30524580
3: ""
}
messageSendClickToSentLatency: 778
conversationIdSHA1: 8480061162880308485
RcsConfig: "NOT_AVAILABLE"
sha256HashMsg: "-8443536869600326524"
sha256HashPrevMsg: "5478611868067030819"
<...>
(b)
Fig. 7: Example of Google Messages ANDROID_MESSAGING
Clearcut logger log entry: (a) protobuf decoded using Google
Protobuf compiler with the --decode_raw option, (b) after
reverse engineering the schema.
ample the number 2 in field 1 encodes the fact that this
is a BUGLE MESSAGE event (Bugle is the internal name
used for the Messages app). Note that the enum labels
here, e.g. BUGLE MESSAGE, are extracted from the app
code and so are Google’s own. Other values encode the
fact that a message was successfully sent as part of a con-
versation (bugleMessageSource) as well as the time
(in milliseconds since 1st Jan 1970) when the message
was sent (currentTime_ms) and the log entry was sent
(timestamp). Observe also the two truncated SHA256 hash
values near the bottom of the message. We shall return to these
shortly, but note that the sha256HashMsg value is a hash
of the time, in hours since 1st Jan 1970, that the message was
sent and of the message content i.e the message text, truncated
to 128 bits. This hash uniquely identifies the message that
was sent. The sha256HashPrevMsg similarly identifies the
previous message sent/received in the conversation. In the
absence of documentation the interpretation of such values is
simply impossible without the kind of time-consuming reverse
engineering carried out here.
Each log source sending data to the Clearcut logger service
uses its own protobuf format for log entries, necessitating
seperate reverse engineering of each in order to decode the
message content.
Figure 8 shows an example of a decoded Google Di-
aler log entry generated in response to manually di-
aling a phone number. The AOSPEventType value
MAIN_CLICK_FAB_TO_OPEN_DIALPAD records the fact
that the dialpad was opened, and the timestamp records
the time when this occurred. As the phone number is
typed a searchQuery event is logged for each digit
typed, see Figure 8(a) for an example log entry sent