Skip to content

Commit d4b4118

Browse files
committed
Version 3.0.0
1 parent 19b13d2 commit d4b4118

File tree

550 files changed

+4632
-60222
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

550 files changed

+4632
-60222
lines changed

Runtime/JsonNet.meta renamed to Android.meta

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Android/BacktraceANRWatchdog.java

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package backtrace.io.backtrace_unity_android_plugin;
2+
import android.os.Debug;
3+
import android.os.Handler;
4+
import android.os.Looper;
5+
import android.util.Log;
6+
7+
import com.unity3d.player.UnityPlayer;
8+
9+
import java.io.PrintWriter;
10+
import java.io.StringWriter;
11+
import java.util.Calendar;
12+
13+
14+
/**
15+
* This is the class that is responsible for monitoring the
16+
* user interface thread and sending an error if it is blocked
17+
*/
18+
public class BacktraceANRWatchdog extends Thread {
19+
20+
private static BacktraceANRWatchdog _instance;
21+
//todo: set anr timeout based on backtrace-unity configuration
22+
static public void watch (String gameObjectName, String methodName){
23+
BacktraceANRWatchdog._instance = new BacktraceANRWatchdog(gameObjectName,methodName);
24+
}
25+
26+
private final static transient String LOG_TAG = BacktraceANRWatchdog.class.getSimpleName();
27+
28+
/**
29+
* Default timeout value in milliseconds
30+
*/
31+
private final static transient int DEFAULT_ANR_TIMEOUT = 5000;
32+
33+
34+
/**
35+
* Enable debug mode - errors will not be sent if the debugger is connected
36+
*/
37+
private final boolean debug;
38+
/**
39+
* Handler for UI Thread - used to check if the thread is not blocked
40+
*/
41+
private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
42+
/**
43+
* Maximum time in milliseconds after which should check if the main thread is not hanged
44+
*/
45+
private int timeout;
46+
47+
48+
/**
49+
* Check if thread should stop
50+
*/
51+
private volatile boolean shouldStop = false;
52+
53+
54+
/**
55+
* Game object name - required by JNI to learn how to call Backtrace Unity plugin
56+
* when library will detect ANR
57+
*/
58+
private String gameObjectName;
59+
60+
61+
/**
62+
* Unity library callback method name
63+
*/
64+
private String methodName;
65+
66+
/**
67+
* Initialize new instance of BacktraceANRWatchdog with default timeout
68+
*/
69+
public BacktraceANRWatchdog(String gameObjectName, String methodName) {
70+
Log.d(LOG_TAG, "Initializing ANR watchdog");
71+
this.methodName = methodName;
72+
this.gameObjectName = gameObjectName;
73+
74+
this.timeout = DEFAULT_ANR_TIMEOUT;
75+
this.debug = false;
76+
this.start();
77+
}
78+
79+
/**
80+
* Method which is using to check if the user interface thread has been blocked
81+
*/
82+
@Override
83+
public void run() {
84+
while (!shouldStop && !isInterrupted()) {
85+
String dateTimeNow = Calendar.getInstance().getTime().toString();
86+
Log.d(LOG_TAG, "ANR WATCHDOG - " + dateTimeNow);
87+
final backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher threadWatcher = new backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher(0, 0);
88+
mainThreadHandler.post(new Runnable() {
89+
@Override
90+
public void run() {
91+
threadWatcher.tickCounter();
92+
}
93+
});
94+
try {
95+
Thread.sleep(this.timeout);
96+
} catch (InterruptedException e) {
97+
Log.d(LOG_TAG, "Thread is interrupted", e);
98+
return;
99+
}
100+
threadWatcher.tickPrivateCounter();
101+
102+
if (threadWatcher.getCounter() == threadWatcher.getPrivateCounter()) {
103+
Log.d(LOG_TAG, "ANR is not detected");
104+
continue;
105+
}
106+
107+
if (debug && (Debug.isDebuggerConnected() || Debug.waitingForDebugger())) {
108+
Log.d(LOG_TAG, "ANR detected but will be ignored because debug mode " +
109+
"is on and connected debugger");
110+
continue;
111+
}
112+
NotifyUnityAboutANR();
113+
}
114+
}
115+
116+
public void NotifyUnityAboutANR() {
117+
String stackTrace = stackTraceToString(Looper.getMainLooper().getThread().getStackTrace());
118+
Log.d(LOG_TAG, stackTrace);
119+
UnityPlayer.UnitySendMessage(this.gameObjectName, this.methodName, stackTrace);
120+
}
121+
122+
public static String stackTraceToString(StackTraceElement[] stackTrace) {
123+
StringWriter sw = new StringWriter();
124+
printStackTrace(stackTrace, new PrintWriter(sw));
125+
return sw.toString();
126+
}
127+
public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
128+
for(StackTraceElement stackTraceEl : stackTrace) {
129+
pw.println(stackTraceEl);
130+
}
131+
}
132+
133+
public void stopMonitoringAnr() {
134+
Log.d(LOG_TAG, "Stop monitoring ANR");
135+
shouldStop = true;
136+
}
137+
}

Android/BacktraceANRWatchdog.java.meta

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Android/BacktraceAttributes.java

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package backtrace.io.backtrace_unity_android_plugin;
2+
3+
import android.content.Context;
4+
import android.os.Build;
5+
import android.os.PowerManager;
6+
import android.util.Log;
7+
8+
import java.io.BufferedReader;
9+
import java.io.File;
10+
import java.io.FileReader;
11+
import java.io.IOException;
12+
import java.io.InputStreamReader;
13+
import java.util.HashMap;
14+
import java.util.Locale;
15+
import java.util.Map;
16+
17+
public class BacktraceAttributes {
18+
19+
private Context context;
20+
private final static transient String LOG_TAG = BacktraceAttributes.class.getSimpleName();
21+
private static Map<String, String> _attributeMapping = new HashMap<String, String>();
22+
static {
23+
_attributeMapping.put("FDSize", "descriptor.count");
24+
_attributeMapping.put("VmPeak", "vm.vma.peak");
25+
_attributeMapping.put("VmSize", "vm.vma.size");
26+
_attributeMapping.put("VmLck", "vm.locked.size");
27+
_attributeMapping.put("VmHWM", "vm.rss.peak");
28+
_attributeMapping.put("VmRSS", "vm.rss.size");
29+
_attributeMapping.put("VmStk", "vm.stack.size");
30+
_attributeMapping.put("VmData", "vm.data");
31+
_attributeMapping.put("VmExe", "vm.exe");
32+
_attributeMapping.put("VmLib", "vm.shared.size");
33+
_attributeMapping.put("VmPTE", "vm.pte.size");
34+
_attributeMapping.put("VmSwap", "vm.swap.size");
35+
36+
_attributeMapping.put("State", "state");
37+
38+
39+
_attributeMapping.put("voluntary_ctxt_switches", "sched.cs.voluntary");
40+
_attributeMapping.put("nonvoluntary_ctxt_switches", "sched.cs.involuntary");
41+
42+
_attributeMapping.put("SigPnd", "vm.sigpnd");
43+
_attributeMapping.put("ShdPnd", "vm.shdpnd");
44+
_attributeMapping.put("Threads", "vm.threads");
45+
46+
_attributeMapping.put("MemTotal", "system.memory.total");
47+
_attributeMapping.put("MemFree", "system.memory.free");
48+
_attributeMapping.put("Buffers", "system.memory.buffers");
49+
_attributeMapping.put("Cached", "system.memory.cached");
50+
_attributeMapping.put("SwapCached", "system.memory.swap.cached");
51+
_attributeMapping.put("Active", "system.memory.active");
52+
_attributeMapping.put("Inactive", "system.memory.inactive");
53+
_attributeMapping.put("SwapTotal", "system.memory.swap.total");
54+
_attributeMapping.put("SwapFree", "system.memory.swap.free");
55+
_attributeMapping.put("Dirty", "system.memory.dirty");
56+
_attributeMapping.put("Writeback", "system.memory.writeback");
57+
_attributeMapping.put("Slab", "system.memory.slab");
58+
_attributeMapping.put("VmallocTotal", "system.memory.vmalloc.total");
59+
_attributeMapping.put("VmallocUsed", "system.memory.vmalloc.used");
60+
_attributeMapping.put("VmallocChunk", "system.memory.vmalloc.chunk");
61+
}
62+
63+
public Map<String, String> GetAttributes(Context unityContext) {
64+
65+
context = unityContext;
66+
HashMap<String, String> result = getProcessAttributes();
67+
result.put("app.storage_used", getAppUsedStorageSize());
68+
result.put("device.cpu.temperature", getCpuTemperature());
69+
result.put("device.is_power_saving_mode", Boolean.toString(isPowerSavingMode()));
70+
result.put("culture", Locale.getDefault().getDisplayLanguage());
71+
result.put("device.sdk", Integer.toString(Build.VERSION.SDK_INT));
72+
result.put("device.manufacturer", Build.MANUFACTURER);
73+
74+
result.entrySet().iterator();
75+
return result;
76+
}
77+
78+
79+
private boolean isPowerSavingMode() {
80+
if (Build.VERSION.SDK_INT < 21) {
81+
return false;
82+
}
83+
PowerManager powerManager = (PowerManager) this.context.getSystemService(Context
84+
.POWER_SERVICE);
85+
return powerManager.isPowerSaveMode();
86+
}
87+
88+
public HashMap<String, String> getProcessAttributes() {
89+
90+
HashMap<String, String> result = new HashMap<>();
91+
92+
int processId = android.os.Process.myPid();
93+
if (processId < 0) {
94+
Log.d(LOG_TAG, "Failed to read process id");
95+
return result;
96+
}
97+
String processAttributes = String.format("/proc/%d/status", processId);
98+
String memoryAttributes = "/proc/meminfo";
99+
return readAttributesFromFile(
100+
memoryAttributes,
101+
readAttributesFromFile(processAttributes, result));
102+
}
103+
104+
private HashMap<String,String> readAttributesFromFile(String path, HashMap<String,String> attributes) {
105+
File file = new File(path);
106+
107+
StringBuilder text = new StringBuilder();
108+
try {
109+
BufferedReader br = new BufferedReader(new FileReader(file));
110+
String line;
111+
112+
while ((line = br.readLine()) != null) {
113+
String[] entry = line.split(":", 2);
114+
String key = entry[0].trim();
115+
if(!_attributeMapping.containsKey(key)){
116+
continue;
117+
}
118+
key = _attributeMapping.get(key);
119+
String value = entry[1].trim();
120+
if(value.endsWith("kB")){
121+
value = value.substring(0,value.lastIndexOf('k')).trim();
122+
}
123+
attributes.put(key, value);
124+
}
125+
br.close();
126+
} catch (IOException e) {
127+
Log.d(LOG_TAG, "Cannot read process information. Reason:" + e.getMessage());
128+
attributes.put("parseError", e.getMessage());
129+
}
130+
131+
return attributes;
132+
}
133+
134+
135+
public String getCpuTemperature() {
136+
Process p;
137+
try {
138+
p = Runtime.getRuntime().exec("cat sys/class/thermal/thermal_zone0/temp");
139+
p.waitFor();
140+
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
141+
142+
String line = reader.readLine();
143+
if (line == null) {
144+
return "0.0";
145+
}
146+
return Float.toString(Float.parseFloat(line) / 1000.0f);
147+
} catch (Exception e) {
148+
return "0.0";
149+
}
150+
}
151+
152+
public String getAppUsedStorageSize() {
153+
long freeSize = 0L;
154+
long totalSize = 0L;
155+
long usedSize = -1L;
156+
try {
157+
Runtime info = Runtime.getRuntime();
158+
freeSize = info.freeMemory();
159+
totalSize = info.totalMemory();
160+
usedSize = totalSize - freeSize;
161+
} catch (Exception e) {
162+
e.printStackTrace();
163+
}
164+
return Long.toString(usedSize);
165+
}
166+
}

Android/BacktraceAttributes.java.meta

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)