mobile/android/base/tests/testANRReporter.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 package org.mozilla.gecko.tests;
michael@0 2
michael@0 3 import org.mozilla.gecko.AppConstants;
michael@0 4
michael@0 5 import android.content.Context;
michael@0 6 import android.content.Intent;
michael@0 7
michael@0 8 import com.jayway.android.robotium.solo.Condition;
michael@0 9
michael@0 10 import java.io.File;
michael@0 11 import java.io.FileReader;
michael@0 12 import java.io.FileWriter;
michael@0 13
michael@0 14 import org.json.JSONObject;
michael@0 15
michael@0 16 /**
michael@0 17 * Tests the proper operation of the ANR reporter.
michael@0 18 */
michael@0 19 public class testANRReporter extends BaseTest {
michael@0 20
michael@0 21 private static final String ANR_ACTION = "android.intent.action.ANR";
michael@0 22 private static final String PING_DIR = "saved-telemetry-pings";
michael@0 23 private static final int WAIT_FOR_PING_TIMEOUT = 10000;
michael@0 24 private static final String ANR_PATH = "/data/anr/traces.txt";
michael@0 25 private static final String SAMPLE_ANR
michael@0 26 = "----- pid 1 at 2014-01-15 18:55:51 -----\n"
michael@0 27 + "Cmd line: " + AppConstants.ANDROID_PACKAGE_NAME + "\n"
michael@0 28 + "\n"
michael@0 29 + "JNI: CheckJNI is off; workarounds are off; pins=0; globals=397\n"
michael@0 30 + "\n"
michael@0 31 + "DALVIK THREADS:\n"
michael@0 32 + "(mutexes: tll=0 tsl=0 tscl=0 ghl=0)\n"
michael@0 33 + "\n"
michael@0 34 + "\"main\" prio=5 tid=1 WAIT\n"
michael@0 35 + " | group=\"main\" sCount=1 dsCount=0 obj=0x41d6bc90 self=0x41d5a3c8\n"
michael@0 36 + " | sysTid=3485 nice=0 sched=0/0 cgrp=apps handle=1074852180\n"
michael@0 37 + " | state=S schedstat=( 0 0 0 ) utm=1065 stm=152 core=0\n"
michael@0 38 + " at java.lang.Object.wait(Native Method)\n"
michael@0 39 + " - waiting on <0x427ab340> (a org.mozilla.gecko.GeckoEditable$5)\n"
michael@0 40 + " at java.lang.Object.wait(Object.java:364)\n"
michael@0 41 + " at org.mozilla.gecko.GeckoEditable$5.run(GeckoEditable.java:746)\n"
michael@0 42 + " at android.os.Handler.handleCallback(Handler.java:733)\n"
michael@0 43 + " at android.os.Handler.dispatchMessage(Handler.java:95)\n"
michael@0 44 + " at android.os.Looper.loop(Looper.java:137)\n"
michael@0 45 + " at android.app.ActivityThread.main(ActivityThread.java:4998)\n"
michael@0 46 + " at java.lang.reflect.Method.invokeNative(Native Method)\n"
michael@0 47 + " at java.lang.reflect.Method.invoke(Method.java:515)\n"
michael@0 48 + " at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)\n"
michael@0 49 + " at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)\n"
michael@0 50 + " at dalvik.system.NativeStart.main(Native Method)\n"
michael@0 51 + "\n"
michael@0 52 + "\"Gecko\" prio=5 tid=16 SUSPENDED\n"
michael@0 53 + " | group=\"main\" sCount=1 dsCount=0 obj=0x426e2b28 self=0x76ae92e8\n"
michael@0 54 + " | sysTid=3541 nice=0 sched=0/0 cgrp=apps handle=1991153472\n"
michael@0 55 + " | state=S schedstat=( 0 0 0 ) utm=1118 stm=145 core=0\n"
michael@0 56 + " #00 pc 00000904 /system/lib/libc.so (__futex_syscall3+4294832136)\n"
michael@0 57 + " #01 pc 0000eec4 /system/lib/libc.so (__pthread_cond_timedwait_relative+48)\n"
michael@0 58 + " #02 pc 0000ef24 /system/lib/libc.so (__pthread_cond_timedwait+64)\n"
michael@0 59 + " #03 pc 000536b7 /system/lib/libdvm.so\n"
michael@0 60 + " #04 pc 00053c79 /system/lib/libdvm.so (dvmChangeStatus(Thread*, ThreadStatus)+34)\n"
michael@0 61 + " #05 pc 00049507 /system/lib/libdvm.so\n"
michael@0 62 + " #06 pc 0004d84b /system/lib/libdvm.so\n"
michael@0 63 + " #07 pc 0003f1df /dev/ashmem/libxul.so (deleted)\n"
michael@0 64 + " at org.mozilla.gecko.mozglue.GeckoLoader.nativeRun(Native Method)\n"
michael@0 65 + " at org.mozilla.gecko.GeckoAppShell.runGecko(GeckoAppShell.java:384)\n"
michael@0 66 + " at org.mozilla.gecko.GeckoThread.run(GeckoThread.java:177)\n"
michael@0 67 + "\n"
michael@0 68 + "----- end 1 -----\n"
michael@0 69 + "\n"
michael@0 70 + "\n"
michael@0 71 + "----- pid 2 at 2013-01-25 13:27:01 -----\n"
michael@0 72 + "Cmd line: system_server\n"
michael@0 73 + "\n"
michael@0 74 + "----- end 2 -----\n";
michael@0 75
michael@0 76 private boolean mDone;
michael@0 77
michael@0 78 private JSONObject readPingFile(final File pingFile) throws Exception {
michael@0 79 final long fileSize = pingFile.length();
michael@0 80 if (fileSize == 0 || fileSize > Integer.MAX_VALUE) {
michael@0 81 throw new Exception("Invalid ping file size");
michael@0 82 }
michael@0 83 final char[] buffer = new char[(int) fileSize];
michael@0 84 final FileReader reader = new FileReader(pingFile);
michael@0 85 try {
michael@0 86 final int readSize = reader.read(buffer);
michael@0 87 if (readSize == 0 || readSize > buffer.length) {
michael@0 88 throw new Exception("Invalid number of bytes read");
michael@0 89 }
michael@0 90 } finally {
michael@0 91 reader.close();
michael@0 92 }
michael@0 93 return new JSONObject(new String(buffer));
michael@0 94 }
michael@0 95
michael@0 96 public void testANRReporter() throws Exception {
michael@0 97 blockForGeckoReady();
michael@0 98
michael@0 99 // Cannot test ANR reporter if it's disabled.
michael@0 100 if (!AppConstants.MOZ_ANDROID_ANR_REPORTER) {
michael@0 101 mAsserter.ok(true, "ANR reporter is disabled", null);
michael@0 102 return;
michael@0 103 }
michael@0 104
michael@0 105 // For the ANR reporter to work, we need to provide sample ANR traces to it.
michael@0 106 // Therefore, we need the ANR file to exist and writable. If not, we don't
michael@0 107 // have the right permissions to create the file, so we just bail.
michael@0 108 final File anrFile = new File(ANR_PATH);
michael@0 109 if (!anrFile.exists()) {
michael@0 110 mAsserter.ok(true, "ANR file does not exist", null);
michael@0 111 return;
michael@0 112 }
michael@0 113 if (!anrFile.canWrite()) {
michael@0 114 mAsserter.ok(true, "ANR file is not writable", null);
michael@0 115 return;
michael@0 116 }
michael@0 117
michael@0 118 final FileWriter anrWriter = new FileWriter(anrFile);
michael@0 119 try {
michael@0 120 anrWriter.write(SAMPLE_ANR);
michael@0 121 } finally {
michael@0 122 anrWriter.close();
michael@0 123 }
michael@0 124
michael@0 125 // Block the UI thread to simulate an ANR
michael@0 126 final Runnable uiBlocker = new Runnable() {
michael@0 127 @Override
michael@0 128 public synchronized void run() {
michael@0 129 while (!mDone) {
michael@0 130 try {
michael@0 131 wait();
michael@0 132 } catch (final InterruptedException e) {
michael@0 133 }
michael@0 134 }
michael@0 135 }
michael@0 136 };
michael@0 137 getActivity().runOnUiThread(uiBlocker);
michael@0 138
michael@0 139 // Make sure our initial ping directory is empty.
michael@0 140 final File pingDir = new File(mProfile, PING_DIR);
michael@0 141 final String[] initialFiles = pingDir.list();
michael@0 142 mAsserter.ok(initialFiles == null || initialFiles.length == 0,
michael@0 143 "Ping directory is empty", null);
michael@0 144
michael@0 145 final Intent anrIntent = new Intent(ANR_ACTION);
michael@0 146 anrIntent.setPackage(AppConstants.ANDROID_PACKAGE_NAME);
michael@0 147 mAsserter.is(anrIntent.getPackage(), AppConstants.ANDROID_PACKAGE_NAME,
michael@0 148 "Successfully set package name");
michael@0 149
michael@0 150 final Context testContext = getInstrumentation().getContext();
michael@0 151 mAsserter.isnot(testContext, null, "testContext should not be null");
michael@0 152
michael@0 153 // Trigger the ANR.
michael@0 154 mAsserter.info("Triggering ANR", null);
michael@0 155 testContext.sendBroadcast(anrIntent);
michael@0 156
michael@0 157 // ANR reporter is supposed to ignore duplicate ANRs.
michael@0 158 // This will be checked later when we look for ping files.
michael@0 159 mAsserter.info("Triggering second ANR", null);
michael@0 160 testContext.sendBroadcast(new Intent(anrIntent));
michael@0 161
michael@0 162 mAsserter.info("Waiting for ping", null);
michael@0 163 waitForCondition(new Condition() {
michael@0 164 @Override
michael@0 165 public boolean isSatisfied() {
michael@0 166 final File[] newFiles = pingDir.listFiles();
michael@0 167 if (newFiles == null || newFiles.length == 0) {
michael@0 168 // Keep waiting.
michael@0 169 return false;
michael@0 170 }
michael@0 171 // Make sure we have a complete file. We skip assertions and catch all
michael@0 172 // exceptions here because the condition may not be satisfied now but may
michael@0 173 // be satisfied later. After the wait is over, we will repeat the same
michael@0 174 // steps with assertions and exceptions.
michael@0 175 try {
michael@0 176 return readPingFile(newFiles[0]).has("slug");
michael@0 177 } catch (final Exception e) {
michael@0 178 return false;
michael@0 179 }
michael@0 180 }
michael@0 181 }, WAIT_FOR_PING_TIMEOUT);
michael@0 182
michael@0 183 mAsserter.ok(pingDir.exists(), "Ping directory exists", null);
michael@0 184 mAsserter.ok(pingDir.isDirectory(), "Ping directory is a directory", null);
michael@0 185
michael@0 186 final File[] newFiles = pingDir.listFiles();
michael@0 187 mAsserter.isnot(newFiles, null, "Ping directory is not empty");
michael@0 188 mAsserter.is(newFiles.length, 1, "ANR reporter wrote one ping");
michael@0 189 mAsserter.ok(newFiles[0].exists(), "Ping exists", null);
michael@0 190 mAsserter.ok(newFiles[0].isFile(), "Ping is a file", null);
michael@0 191 mAsserter.ok(newFiles[0].canRead(), "Ping is readable", null);
michael@0 192 mAsserter.info("Found ping file", newFiles[0].getPath());
michael@0 193
michael@0 194 // Check standard properties required by Telemetry server.
michael@0 195 final JSONObject pingObject = readPingFile(newFiles[0]);
michael@0 196 mAsserter.ok(pingObject.has("slug"), "Ping has slug property", null);
michael@0 197 mAsserter.ok(pingObject.has("reason"), "Ping has reason property", null);
michael@0 198 mAsserter.ok(pingObject.has("payload"), "Ping has payload property", null);
michael@0 199
michael@0 200 final JSONObject pingPayload = pingObject.getJSONObject("payload");
michael@0 201 mAsserter.ok(pingPayload.has("ver"), "Payload has ver property", null);
michael@0 202 mAsserter.ok(pingPayload.has("info"), "Payload has info property", null);
michael@0 203 mAsserter.ok(pingPayload.has("androidANR"), "Payload has androidANR property", null);
michael@0 204
michael@0 205 final JSONObject pingInfo = pingPayload.getJSONObject("info");
michael@0 206 mAsserter.ok(pingInfo.has("reason"), "Info has reason property", null);
michael@0 207 mAsserter.ok(pingInfo.has("appName"), "Info has appName property", null);
michael@0 208 mAsserter.ok(pingInfo.has("appUpdateChannel"), "Info has appUpdateChannel property", null);
michael@0 209 mAsserter.ok(pingInfo.has("appVersion"), "Info has appVersion property", null);
michael@0 210 mAsserter.ok(pingInfo.has("appBuildID"), "Info has appBuildID property", null);
michael@0 211
michael@0 212 // Do some profile clean up. This is not absolutely necessary because the profile
michael@0 213 // is blown away after test runs anyways, so we don't check return values here.
michael@0 214 for (final File ping : newFiles) {
michael@0 215 ping.delete();
michael@0 216 }
michael@0 217 pingDir.delete();
michael@0 218
michael@0 219 // Unblock UI thread
michael@0 220 synchronized (uiBlocker) {
michael@0 221 mDone = true;
michael@0 222 uiBlocker.notify();
michael@0 223 }
michael@0 224
michael@0 225 // Clear the sample ANR
michael@0 226 final FileWriter anrClearer = new FileWriter(anrFile);
michael@0 227 anrClearer.close();
michael@0 228 }
michael@0 229 }

mercurial