Abstract|We present newly-found vulnerabilities in the Firefox Android Application. Exploiting them allows a malicious application to successfully derandomize the Firefox prole directory name in a practical amount of time and exltrate sensitive data (such as cookies and cached information) which reside in that directory, breaking Android's sandbox.
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Overtaking Firefox Profiles: Vulnerabilities in Firefox for Android
1. 1
OVERTAKING FIREFOX PROFILES
Vulnerabilities in Firefox for Android
Roee Hay
IBM Security Systems
roeeh@il.ibm.com
Abstract—We present newly-found vulnerabili-
ties in the Firefox Android Application. Exploiting
them allows a malicious application to successfully
derandomize the Firefox profile directory name in
a practical amount of time and exfiltrate sensitive
data (such as cookies and cached information)
which reside in that directory, breaking Android’s
sandbox.
Index Terms—CVE-2014-1484; CVE-2014-
1506; CVE-2014-1515; CVE-2014-1516.
I. Android basics
A. Threat model
Android applications are executed in a sandbox
environment to ensure that no application can access
sensitive information held by another without proper
privileges. For example, Android’s browser appli-
cation holds sensitive information such as cookies,
cache and history which cannot be accessed by third-
party apps. An android application may request spe-
cific privileges (permissions) during its installation;
if granted by the user, the capabilities are extended.
Permissions are defined under the application’s man-
ifest file, namely AndroidManifest.xml.
B. Activities and Services
Android applications are composed of compo-
nents of different types including activities and
services. An Activity, implemented by the an-
droid.content.Activity class [1], defines a single
UI, e.g. a browsing window or a preferences screen.
Services [2] are application components that are used
for background tasks.
C. Inter-Process Communication (IPC) and Intents
Android applications communicate with each other
through Intents. These are messaging objects that
contain several attributes such as an action, data,
category, target and extras. The data attribute is
a URI which identifies the Intent (e.g. tel:0422123).
Each Intent can also contain extra data fields, namely
Intent extras, which reside inside a Bundle (imple-
mented by the android.os.Bundle class [3]). Intent
extras can be set by using the Intent.putExtra
API or by manipulating the extras Bundle directly.
It is important to emphasize that intents provide a
channel for a malicious application to inject malicious
data into a target, potentially vulnerable application.
Intents can have either explicit or implicit destina-
tion, depending whether targets are specified or not.
Intents can be broadcast, passed to the startActiv-
ity call (when an application starts another activ-
ity), or passed to the startService call (when an
application starts a service). Under the application’s
manifest file, an application component may claim
whether it can be invoked externally using an Intent,
and if so which set of permissions is required. We
define a public application component as one which
can be invoked externally by a (potentially malicious)
application without any permissions. All other com-
ponents are defined as private, i.e. they can only be
invoked by other application components of the same
package, or externally with proper privileges.
II. Generation of the Profile Directory
Firefox stores the personal data under the profile
directory, located at files/mozilla/X.default/
where X is a randomly chosen 8-byte word over
the alphanumeric alphabet [a-z0-9]. The gener-
ation of X.default is implemented at GeckoPro-
file.saltProfileName (Figure II.1).
Since the profile directory name is random, Firefox
stores a mapping under the files/mozilla/pro-
files.ini file (Figure II.2)
If Firefox does not find a valid profile, for example
due to a missing profiles.ini, it creates a new one
by invoking GeckoProfile.createProfileDir.
III. Vulnerabilities
A. Profile Directory Name Weak Randomization
The Math.random() static method returns a uni-
formly distributed pseudo-random number between
2. 2
1 private static String
2 saltProfileName ( String name)
3 {
4 String allowedChars =
5 ”abcdefghijklmnopqrstuvwxyz0123456789 ” ;
6
7 StringBuilder s a l t =
8 new StringBuilder ( 1 6 ) ;
9
10 for ( int i = 0; i < 8; i++) {
11 s a l t . append ( allowedChars . charAt (( int )
12 (Math . random () ∗
13 allowedChars . length ( ) ) ) ) ;
14 }
15 s a l t . append ( ’ . ’ ) ;
16 s a l t . append (name ) ;
17 return s a l t . toString ( ) ;
18 }
Figure II.1. GeckoProfile.saltProfileName(String name)
[Profile0]
Default=1
Name=default
IsRelative=1
Path=475jbgu6.default
[General]
StartWithLastProfile=1
Figure II.2. profiles.ini
0 and 1. In Android, the implementation is under
libcore1
:
1 public static synchronized double random ()
2 {
3 i f ( random == null )
4 {
5 random = new Random ( ) ;
6 }
7 return random . nextDouble ( ) ;
8 }
Figure III.1. Math.random()
We can see that this method relies on the
java.util.Random class which is seeded in its de-
fault constructor. In Android 4.4 and below, it is
implemented as follows2
:
1https://android.googlesource.com/platform/libcore/
2https://android.googlesource.com/platform/libcore/+/
android-4.4 r1.2/luni/src/main/java/java/util/Random.java
1 public Random()
2 {
3 setSeed ( System . currentTimeMillis ()
4 + System . identityHashCode ( this ) ) ;
5 }
Figure III.2. java.util.Random’s constructor
Therefore the seed depends on a couple of values:
1) The current time in milliseconds precision
(System.currentTimeMillis())
2) The identity hash code of the Random object
(System.identityHashCode(this))
System.identityHashCode is implemented by na-
tive code in the Dalvik VM implementation3
. The
identity hash code value is the object’s Virtual Ad-
dress (VA) which resides in the heap of the Dalvik
VM process.
GeckoProfile.saltProfileName uses
Math.random() which is cryptographically insecure.
We have seen that its seed relies on the inner-
Random object creation time (in ms precision) and
its VA. Both factors are not random. The creation
time can be leaked by an adversary (see IV-A1b)
and the VA lacks randomness due to ineffective
ASLR in the Dalvik VM process [4], [5]. Since the
Dalvik VM is forked from the Zygote process, the
VA of the Dalvik Heap is the same for all Android
Dalvik applications. To conclude, the seed is not
random, thus the profile directory name entropy is
far from the ideal 41.36 random bits (log2 368
) and
can be predicted by the adversary as we will see
next.
B. Profile Directory Name Leaks to Android System
Log
The random Profile Directory Name is written to
the Android System Log (logcat) in various locations.
For instance, upon Firefox launch, the following data
is written:
D/GeckoProfile( 4766): Found profile dir:
/data/data/.../files/mozilla/24pd90uh.default
In Android 4.0 and below, the Android log can easily
be read by all applications including malicious ones
by acquiring the READ_LOGS permission. Android 4.1
has introduced a change to this behavior to prevent
such log leakage attacks: the READ_LOGS permission
is no longer required, however applications can only
listen to their own log. In section IV-B we show how
a malicious app can manipulate Firefox to leak its
own private log in order to overcome this obstacle.
3https://android.googlesource.com/platform/dalvik.git/+/
android-4.4 r1.2/vm/Sync.cpp
3. 3
C. Automatic File Download to SD Card
Any file which cannot be rendered by Fire-
fox is automatically downloaded to the SD card
(/mnt/sdcard/Download), a folder which can be
read by a malicious application by acquiring the
READ_EXTERNAL_STORAGE permission. Interestingly,
this permission was not even enforced before Android
4.44
. This allows a malicious application to extract
non-renderable data such as the cookies database,
once it has managed to derandomize the profile
directory name.
D. Crash Reporter File Manipulation
The org.mozilla.gecko.CrashReporter class is
a public activity. Its purpose is to send crash dumps
to Mozilla when needed (Figure III.3). The CrashRe-
porter activity receives the dump file path as an
input (an Intent extra parameter). When the activity
is launched, its onCreate method (Figure III.4) is
executed and the following actions take place:
1) Using the moveFile (Figure III.5) method, the
given minidump file is moved to the pending
minidumps path, files/mozilla/Crash Re-
ports/pending.
2) A meta-data filename is deduced from the given
minidump file path, by replacing all ’.dmp’
occurrences with ’.extra’. i.e. <filename>.dmp
becomes <filename>.extra.
3) The meta-data file is moved to the pending
minidumps path using the moveFile method.
4) The meta-data file is parsed as a key/value file
format (Figure III.6). The target server URL
(i.e. the one that the crash information is sent
to) is specified here using the ServerURL key.
5) The crash dialog is presented to the user (Fig-
ure III.3).
If the user presses the Close or Restart buttons with
the Send report check-box enabled, the minidump
alongside with other sensitive information is sent
to the specified server by calling the sendReport
method. It should be noted that if the user has
also checked the Include the address check-box, then
Android logs are sent as well.
The CrashReporter activity consumes the
minidump path from the input intent (Figure III.4,
Line 4) although it should be considered untrusted
data since the activity is public as defined in
the Android Manifest file. Therefore, a malicious
application can control the source path of the
moved minidump file and the deduced extra file
4http://developer.android.com/reference/android/
Manifest.permission.html#READ EXTERNAL STORAGE
Figure III.3. Crash Reporter dialog
(Figure III.4, Lines 8, 11). We will see in the next
section that this allows that attacker to control the
destination server for the crash report, hence the
response value used as a file path in Figure III.7,
Line 19 should be untrusted as well.
IV. Exploitation
The attacker (by the use of a malicious appli-
cation) can exploit a subset of the aforementioned
vulnerabilities in order to:
1) Derandomize the profile directory path.
2) Exfiltrate sensitive data (such as cookies and
cached information) from the profile directory.
In this section we describe several attractive exploita-
tion suites.
A. Suite I: Exploiting Vulnerabilities III-A, III-C and
optionally III-D
1) Derandomizing the Profile Path: Let Y be the
seed chosen by Firefox. The goal of the attacker is to
derandomize it by recording some value which shares
a strong relation with it. Both the VA and the time
parts of the seed cannot be entirely determined by
the attacker, however, most of their bits can be leaked
to the attacker using simple actions:
a) Derandomizing the VA Value: To obtain
parts of the VA, as per the ineffective ASLR, the
attacker can query its own process using the Sys-
tem.identitiyHashCode routine on some object.
4. 4
b) Derandomizing the Time Value: The ms
time value can be leaked in two different ways.
First, if Firefox had been installed after the ma-
licious app, the latter can record the first Firefox
run by simply monitoring the device’s process list.
Otherwise, the attacker app can exploit Vulnera-
bility III-D to move the profiles.ini file (which
has a deterministic path) to the different direc-
tory. The exploitation is done by sending an Intent
to the Crash Reporter with minidumpPath Intent
extra set to /data/data/org.mozilla.firefox/-
files/mozilla/profiles.ini. Firefox will create a
new profile on its next run, which can be forced by
crashing it (this can be done by exploiting Vulnera-
bility III-D, sending an Intent to the Crash Reporter
without a minidumpPath extra). Again the attacker
can record the Firefox launch time.
Let X be the attacker’s inaccurate sample where
X = V A + MeasuredTime. Let ε be the error,
i.e. ε = Y − X. In our brute-force attack we try
values in the order of their inferred probabilities
which can be computed offline by the attacker (see
Section V). Let N be the number of attempts until
a success, then the expected number of attempts is
E(N) =
n
k=1 k·p(k) where {p(k)}n
k=1 are the ordered
inferred probabilities (p(1) ≥ p(2) ≥ · · · ≥ p(n)).
Please note that the expression for E(N) proves
that this is the optimal search algorithm (in terms
of the expectation). A simpler model is to assume
that ε is a (discrete) bell-curve with the center
estimated by ¯ε = ¯x-¯y. It can be shown that E(N) =
O(E|X − EX|) = O (σε) so a more narrow bell-
curve yields a shorter attack time (on average). By
using the inferred probabilities of ε and the sampled
seed, X, the attacker creates a list of profile names
by mimicking the GeckoProfile.saltProfileName
implementation (this computation can be also done
off the device and downloaded from the attacker).
2) Data Exfiltration: This phase is online. The
attacker creates a specially crafted world-readable
HTML file and commands Firefox to load it (by using
an Intent). This file includes the list of profile names
ordered by their probabilities generated previously.
The JavaScript code in the HTML file goes over the
list, searching for the correct profile. When there is
a match, it can download any file under the profiles
directory by creating an iframe targeting the file-
name. As per Vulnerability III-C, if Firefox cannot
render the file, it will automatically download the file
to the SD card (/mnt/sdcard/Download), a folder
which can be read by the attacker.
B. Suite II: Exploiting Vulnerabilities III-B, III-C
and optionally III-D
1) Derandomizing the Profile Path : On Android
4.0 and below, the Android System Log can easily be
read by the malicious app. This allows the malicious
app to exploit Vulnerability III-B and deduce the
profile directory path.
Android 4.1 prevents this attack as applications
can only listen to their own logs. Since Firefox sends
its own private log alongside the crash report (see
Section III-D) , Vulnerability III-D can be exploited
for sending the logs to the attacker:
• The malicious app creates two world
readable files under its data directory:
/data/data/<malicious app>/foo.dmp with
an arbitrary content (can be left empty) and
/data/data/<malicious app>/foo.extra
which contains the attacker’s server,
ServerURL=http://<attacker>/.
• The malicious app generates an Intent ob-
ject which targets the CrashReporter activity
with a minidumpPath parameter set to /data/-
data/<malicious app>/foo.dmp
After the above actions take place, according to the
operation of the CrashReporter activity (see Section
III-D), Firefox will move foo.dmp and foo.extra
from the malicious app data directory to the Fire-
fox crash reports pending path and then parse
foo.extra for key-value pairs. Since the extra file
now contains the attacker’s IP as the ServerURL, if
the user pressed one of the buttons on the CrashRe-
porter dialog, Firefox would send the crash report
to the attacker. If the user has also checked the
Include the address check-box, then Firefox would
also append the Android Log output, which contains
the Firefox private logs that include the random
profile directory name. It should be noted that since
Firefox only sends a 200 lines window of the log, the
leaked path can be out of that window since it is
logged upon Firefox’s launch. In order to make sure
that the path is within the window, the attacker can
restart Firefox by crashing it. This can be easily done
by invoking the CrashReporter activity without a
minidumpPath parameter.
2) Data Exfiltration: Once the attacker has learnt
the profile path, he can leak files by exploiting Vul-
nerability III-C. The attacker simply invokes Firefox
using an Intent with a payload set to the target file
path.
C. Suite III: Exploiting Vulnerabilities III-B and
III-D
1) Derandomizing the Profile Path Seed: This part
is exactly as described in Section IV-B1.
5. 5
2) Data Exfiltration: Here we exploit
Vulnerability III-D. We indirectly inject the
ServerURL=http://<attacker> string to the target
file and trick Firefox to use this file as the minidump
extra. For instance, by using this method, the
attacker can leak the cache. First, he opens Firefox
(using an Intent) on an attacker’s controlled website,
which contains the above string in its HTML body
(Figure IV.1). After the cache has been prepared,
the attacker can leak it by generating another Intent
that targets the CrashReporter activity, with the
minidump path parameter set to the cache file. Since
the cache file path has no ’.dmp’ substring, the
computed extra file will be the same, and the target
server URL will be parsed out of the cache file.
1 <HTML>
2 <BODY>
3 ServerURL=http : //<ATTACKER>
4 </BODY>
5 </HTML>
Figure IV.1. Injected payload into Firefox’s cache
V. Evaluation
We tested our Suite I exploit on Firefox 25.0.1
running on Samsung GT-I9500 Galaxy S4 device
equipped with Android 4.2.2. In order to infer the
probabilities of ε we ran 404 independent runs of the
following test:
1) Call Math.Random() and retrieve its identi-
tyHashCode (Figure V.1)
2) Start monitoring the process list in a frequency
of 20 Hz for recording the Firefox launch time.
3) Remove the profiles.ini file from the Firefox
directory by exploiting Vulnerability III-D.
4) Record the created profile directory.
5) Kill Firefox.
6) Restart Firefox.
7) Print the needed values.
1 Math . random ( ) ;
2 Field f = Math . class .
3 getDeclaredField ( ”random ” ) ;
4 f . s e t A c c e s s i b l e ( true ) ;
5 Random r = (Random) f . get ( null ) ;
6 Long addr = System . identityHashCode ( r ) ;
Figure V.1. Retrieving the identityHashCode of the Math
inner Random object
For example, for each run we received and recorded
the following data:
Sampled VA: 42dc6cd8
Sampled Time: 1385337348079
Sampled Seed: 142cf66ccc7
Created profile: xa1x453r.default
Later we calculated the real seed and ε by an offline
brute-force. For example, for the data above, the real
seed is 1386459232784 and ε = 142665.
We witnessed three strong linear correlations be-
tween Y and X (Figure V.2). We believe that the
reason for the less dense lines rely on Dalvik Heap
internals which caused the offset to ’jump’ with a
fixed number for a few tests (i.e. the probability for
this to happen is low).
Ϭ
ϮϬϬϬϬϬϬ
ϰϬϬϬϬϬϬ
ϲϬϬϬϬϬϬ
ϴϬϬϬϬϬϬ
ϭϬϬϬϬϬϬϬ
ϭϮϬϬϬϬϬϬ
ϭϰϬϬϬϬϬϬ
ϭϲϬϬϬϬϬϬ
Ϭ ϮϬϬϬϬϬϬ ϰϬϬϬϬϬϬ ϲϬϬϬϬϬϬ ϴϬϬϬϬϬϬ ϭϬϬϬϬϬϬϬ ϭϮϬϬϬϬϬϬ ϭϰϬϬϬϬϬϬ
Figure V.2. Linear correlation between the real seed and the
sampled one
We created a histogram for inferring the distribu-
tion of ε (Figure V.3) and calculated the expected
number of attempts, E(N), which is 152779.65 and
is equivalent to 17.22 bits. Note that the Shannon
entropy is very close, 18.63 bits. We’ve got an entropy
which is much lower than the ideal 64 bits (the java
long primitive size) seed entropy, thus the attack is
feasible.
Ϭ
Ϭ͘ϬϮ
Ϭ͘Ϭϰ
Ϭ͘Ϭϲ
Ϭ͘Ϭϴ
Ϭ͘ϭ
Ϭ͘ϭϮ
Ϭ͘ϭϰ
ͲϭϬϬϬϬϬ ϮϬϬϬϬϬ ϱϬϬϬϬϬ ϴϬϬϬϬϬ ϭϭϬϬϬϬϬ ϭϰϬϬϬϬϬ ϭϳϬϬϬϬϬ
Figure V.3. ε Histogram
We then adhered to the steps of section IV-A,
taken the simpler approach where we assert a sym-
metric bell curve. Since we received three linear
6. 6
correlations, we have taken a slightly different ap-
proach. We denote p1, p2, p3 as the probabilities for
the error to be taken from each curve and assert that
each error is normally distributed with its respective
variance (the actual discrete error is the rounded
value, see Figure V.4). Therefore ε1 ∼ N 0, σ2
1 with
probability p1 , ε2 ∼ N 0, σ2
2 with probability p2
and ε3 ∼ N 0, σ2
3 with probability p3. We brute-
force in the order of the probabilities. We ran our
exploit and successfully caused Firefox to download
sensitive files into the SD card which can be read by
the attacker (Figure V.5). It should be noted that
according to the ’normalized’ model, the expected
number of tries is 214373.3 which is equivalent to
17.709 bits.
Ϭ
Ϭ͘ϬϮ
Ϭ͘Ϭϰ
Ϭ͘Ϭϲ
Ϭ͘Ϭϴ
Ϭ͘ϭ
Ϭ͘ϭϮ
ͲϭϬϬϬϬϬ ϮϬϬϬϬϬ ϱϬϬϬϬϬ ϴϬϬϬϬϬ ϭϭϬϬϬϬϬ ϭϰϬϬϬϬϬ ϭϳϬϬϬϬϬ
Figure V.4. Normalized−ε histogram
VI. Identifiers & Fix Versions
Vulnerability CVE ID Fix Version
III-A CVE-2014-1516 TBA5
III-B CVE-2014-1484 Firefox 27
III-C CVE-2014-1515 Firefox 28.0.1
III-D CVE-2014-1506 Firefox 28
VII. Disclosure Timeline
03/25/2014 Public disclosure.
03/25/2014 Firefox 28.0.1 is released, fixing
Vulnerability III-C
03/18/2014 Firefox 28 is released, fixing
Vulnerability III-D
03/15/2014 Permission granted.
03/12/2014 Requested permission to disclose
Vulnerability III-A despite lack of fix.
02/04/2014 Firefox 27 is released, fixing
Vulnerability III-B
11/28/2013 Reported Vulnerabilities.
5As its severity is now much lower with the CVE-2014-1515
fix, we were allowed by Mozilla to publicly disclose this unfixed
vulnerability.
Figure V.5. Automatic File Download (exploiting Vulnerabil-
ity III-C)
References
[1] Activity class reference. http://developer.android.com/
reference/android/app/Activity.html.
[2] Service class reference. http://developer.android.com/
reference/android/app/Service.html.
[3] Bundle class reference. http://developer.android.com/
reference/android/os/Bundle.html.
[4] Byoungyoung Lee, Long Lu, Tielei Wang, Taesoo Kim, and
Wenke Lee. From Zygote to Morula: Fortifying Weakened
ASLR on Android. In IEEE Symposium on Security and
Privacy, 2014.
[5] Jon Oberheide. A look at ASLR in An-
droid Ice Cream Sandwich 4.0, February
2012. https://www.duosecurity.com/blog/
a-look-at-aslr-in-android-ice-cream-sandwich-4-0.
7. 7
1 @Override
2 public void onCreate ( Bundle savedInstanceState ) {
3 . . .
4 String passedMinidumpPath = getIntent ( ) . getStringExtra (PASSED MINI DUMP KEY) ;
5 F i l e passedMinidumpFile = new F i l e ( passedMinidumpPath ) ;
6 F i l e pendingDir = new F i l e ( g e t F i l e s D i r ( ) , PENDING SUFFIX) ;
7 pendingDir . mkdirs ( ) ;
8 mPendingMinidumpFile = new F i l e ( pendingDir , passedMinidumpFile . getName ( ) ) ;
9 moveFile ( passedMinidumpFile , mPendingMinidumpFile ) ;
10 F i l e e x t r a s F i l e = new F i l e ( passedMinidumpPath . r e p l a c e A l l ( ” .dmp” , ” . extra ” ) ) ;
11 mPendingExtrasFile = new F i l e ( pendingDir , e x t r a s F i l e . getName ( ) ) ;
12 moveFile ( extrasFile , mPendingExtrasFile ) ;
13 mExtrasStringMap = new HashMap<String , String >();
14 readStringsFromFile ( mPendingExtrasFile . getPath ( ) , mExtrasStringMap ) ;
15 . . .
16 }
Figure III.4. onCreate method under CrashReporter
1 private boolean moveFile ( F i l e inFile , F i l e outFile ) {
2 Log . i (LOGTAG, ”moving ” + i n F i l e + ” to ” + outFile ) ;
3 i f ( i n F i l e . renameTo ( outFile ))
4 return true ;
5 try {
6 outFile . createNewFile ( ) ;
7 Log . i (LOGTAG, ”couldn ’ t rename minidump f i l e ” ) ;
8 // so copy i t instead
9 FileChannel inChannel = new FileInputStream ( i n F i l e ) . getChannel ( ) ;
10 FileChannel outChannel = new FileOutputStream ( outFile ) . getChannel ( ) ;
11 long t r a n s f e r r e d = inChannel . transferTo (0 , inChannel . s i z e ( ) , outChannel ) ;
12 inChannel . c l o s e ( ) ;
13 outChannel . c l o s e ( ) ; pr i or to
14 i f ( t r a n s f e r r e d > 0)
15 i n F i l e . d e l e t e ( ) ;
16 } catch ( Exception e ) {
17 Log . e (LOGTAG, ”exception while copying minidump f i l e : ” , e ) ;
18 return false ;
19 }
20 return true ;
21 }
Figure III.5. moveFile method under CrashReporter
8. 8
1 private boolean readStringsFromFile ( String filePath , Map<String , String> stringMap ) {
2 try {
3 BufferedReader reader = new BufferedReader (new FileReader ( f i l e P a t h ) ) ;
4 return readStringsFromReader ( reader , stringMap ) ;
5 } catch ( Exception e ) {
6 Log . e (LOGTAG, ”exception while reading s t r i n g s : ” , e ) ;
7 return false ;
8 }
9 }
10
11 private boolean readStringsFromReader ( BufferedReader reader , Map<String , String> stringMap )
12 throws IOException {
13 String l i n e ;
14 while (( l i n e = reader . readLine ( ) ) != null ) {
15 int equalsPos = −1;
16 i f (( equalsPos = l i n e . indexOf ( ’=’ )) != −1) {
17 String key = l i n e . substring (0 , equalsPos ) ;
18 String val = unescape ( l i n e . substring ( equalsPos + 1 ) ) ;
19 stringMap . put ( key , val ) ;
20 }
21 }
22 reader . c l o s e ( ) ;
23 return true ;
24 }
Figure III.6. File parsing under CrashReporter
1 private void sendReport ( F i l e minidumpFile , Map<String , String> extras , F i l e e x t r a s F i l e ) {
2 final CheckBox includeURLCheckbox = ( CheckBox ) findViewById (R. id . i n c l u d e u r l ) ;
3 String spec = extras . get (SERVER URL KEY) ;
4 . . .
5 try {
6 URL url = new URL( spec ) ;
7 HttpURLConnection conn = ( HttpURLConnection ) url . openConnection ( ) ;
8 . . .
9 i f ( Build .VERSION.SDK INT >= 16 && includeURLCheckbox . isChecked ( ) ) {
10 sendPart ( os , boundary , ”Android Logcat ” , readLogcat ( ) ) ;
11 }
12 . . .
13 sendFile ( os , boundary , MINI DUMP PATH KEY, minidumpFile ) ;
14 . . .
15 i f ( conn . getResponseCode () == HttpURLConnection .HTTP OK) {
16 F i l e submittedDir = new F i l e ( g e t F i l e s D i r ( ) , SUBMITTED SUFFIX) ;
17 . . .
18 String crashid = responseMap . get ( ”CrashID ” ) ;
19 F i l e f i l e = new F i l e ( submittedDir , crashid + ” . txt ” ) ;
20 FileOutputStream f o s = new FileOutputStream ( f i l e ) ;
21 f o s . write ( ”Crash ID : ” . getBytes ( ) ) ;
22 f o s . write ( crashid . getBytes ( ) ) ;
23 f o s . c l o s e ( ) ;
24 }
25 . . .
26 }
27 . . .
28 }
Figure III.7. sendReport under CrashReporter