mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 09:33:49 +02:00
Integrate Breakpad in android Interface
This commit is contained in:
parent
082c1fce52
commit
8869af069e
7 changed files with 242 additions and 9 deletions
|
@ -24,7 +24,8 @@ android {
|
|||
'-DRELEASE_TYPE=' + RELEASE_TYPE,
|
||||
'-DBUILD_BRANCH=' + BUILD_BRANCH,
|
||||
'-DDISABLE_QML=OFF',
|
||||
'-DDISABLE_KTX_CACHE=OFF'
|
||||
'-DDISABLE_KTX_CACHE=OFF',
|
||||
'-DUSE_BREAKPAD=' + (project.hasProperty("BACKTRACE_URL") && project.hasProperty("BACKTRACE_TOKEN") ? 'ON' : 'OFF');
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
@ -43,6 +44,10 @@ android {
|
|||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
buildConfigField "String", "BACKTRACE_URL", "\"" + (project.hasProperty("BACKTRACE_URL") ? BACKTRACE_URL : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (project.hasProperty("BACKTRACE_TOKEN") ? BACKTRACE_TOKEN : '') + "\""
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
@ -50,6 +55,8 @@ android {
|
|||
project.hasProperty("HIFI_ANDROID_KEYSTORE_PASSWORD") &&
|
||||
project.hasProperty("HIFI_ANDROID_KEY_ALIAS") &&
|
||||
project.hasProperty("HIFI_ANDROID_KEY_PASSWORD")? signingConfigs.release : null
|
||||
buildConfigField "String", "BACKTRACE_URL", "\"" + (project.hasProperty("BACKTRACE_URL") ? BACKTRACE_URL : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (project.hasProperty("BACKTRACE_TOKEN") ? BACKTRACE_TOKEN : '') + "\""
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,22 +8,43 @@ import android.app.Activity;
|
|||
|
||||
import android.content.DialogInterface;
|
||||
import android.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
public class PermissionChecker extends Activity {
|
||||
private static final int REQUEST_PERMISSIONS = 20;
|
||||
|
||||
private static final boolean CHOOSE_AVATAR_ON_STARTUP = false;
|
||||
private static final String TAG = "Interface";
|
||||
private static final String ANNOTATIONS_JSON = "annotations.json";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -31,13 +52,20 @@ public class PermissionChecker extends Activity {
|
|||
if (CHOOSE_AVATAR_ON_STARTUP) {
|
||||
showMenu();
|
||||
}
|
||||
this.requestAppPermissions(new
|
||||
String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.RECORD_AUDIO,
|
||||
Manifest.permission.CAMERA}
|
||||
,2,REQUEST_PERMISSIONS);
|
||||
|
||||
Thread networkThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
UploadCrashReports();
|
||||
runOnUiThread(() -> requestAppPermissions(new
|
||||
String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.RECORD_AUDIO,
|
||||
Manifest.permission.CAMERA}
|
||||
,2,REQUEST_PERMISSIONS));
|
||||
}
|
||||
});
|
||||
networkThread.start();
|
||||
|
||||
}
|
||||
|
||||
|
@ -125,5 +153,88 @@ public class PermissionChecker extends Activity {
|
|||
}
|
||||
}
|
||||
|
||||
public void UploadCrashReports()
|
||||
{
|
||||
try
|
||||
{
|
||||
String parameters = getAnnotationsAsUrlEncodedParameters();
|
||||
URL url = new URL(BuildConfig.BACKTRACE_URL+ "/post?format=minidump&token=" + BuildConfig.BACKTRACE_TOKEN + (parameters.isEmpty() ? "" : ("&" + parameters)));
|
||||
// Check if a crash .dmp exists
|
||||
File[] matchingFiles = getFilesByExtension(getObbDir(), "dmp");
|
||||
for (File file : matchingFiles)
|
||||
{
|
||||
int size = (int) file.length();
|
||||
byte[] bytes = new byte[size];
|
||||
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
|
||||
buf.read(bytes, 0, bytes.length);
|
||||
buf.close();
|
||||
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setChunkedStreamingMode(0);
|
||||
|
||||
OutputStream ostream = urlConnection.getOutputStream();
|
||||
|
||||
OutputStream out = new BufferedOutputStream(ostream);
|
||||
out.write(bytes, 0, size);
|
||||
|
||||
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
|
||||
in.read();
|
||||
if (urlConnection.getResponseCode() == 200) {
|
||||
file.delete();
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e(TAG, "Error uploading breakpad dumps", e);
|
||||
}
|
||||
}
|
||||
|
||||
private File[] getFilesByExtension(File dir, final String extension)
|
||||
{
|
||||
return dir.listFiles(pathName -> getExtension(pathName.getName()).equals(extension));
|
||||
}
|
||||
|
||||
private String getExtension(String fileName)
|
||||
{
|
||||
String extension = "";
|
||||
|
||||
int i = fileName.lastIndexOf('.');
|
||||
int p = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
|
||||
|
||||
if (i > p)
|
||||
{
|
||||
extension = fileName.substring(i+1);
|
||||
}
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
|
||||
public String getAnnotationsAsUrlEncodedParameters() {
|
||||
String parameters = "";
|
||||
File annotationsFile = new File(getObbDir(), ANNOTATIONS_JSON);
|
||||
if (annotationsFile.exists()) {
|
||||
JsonParser parser = new JsonParser();
|
||||
try {
|
||||
JsonObject json = (JsonObject) parser.parse(new FileReader(annotationsFile));
|
||||
for (String k: json.keySet()) {
|
||||
if (!json.get(k).getAsString().isEmpty()) {
|
||||
String key = k.contains("/") ? k.substring(k.indexOf("/") + 1) : k;
|
||||
if (!parameters.isEmpty()) {
|
||||
parameters += "&";
|
||||
}
|
||||
parameters += URLEncoder.encode(key, "UTF-8") + "=" + URLEncoder.encode(json.get(k).getAsString(), "UTF-8");
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Error reading annotations file", e);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(TAG, "Error reading annotations file", e);
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
|
22
cmake/macros/TargetBreakpad.cmake
Normal file
22
cmake/macros/TargetBreakpad.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Copyright 2018 High Fidelity, Inc.
|
||||
# Created by Gabriel Calero & Cristian Duarte on 2018/03/13
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_BREAKPAD)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/breakpad)
|
||||
set(BREAKPAD_INCLUDE_DIRS "${INSTALL_DIR}/include" CACHE TYPE INTERNAL)
|
||||
set(LIB_DIR ${INSTALL_DIR}/lib)
|
||||
list(APPEND BREAKPAD_LIBRARIES ${LIB_DIR}/libbreakpad_client.a)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BREAKPAD_INCLUDE_DIRS})
|
||||
if (USE_BREAKPAD)
|
||||
add_definitions(-DHAS_BREAKPAD)
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${TARGET_NAME} ${BREAKPAD_LIBRARIES})
|
||||
endmacro()
|
||||
|
||||
|
|
@ -232,6 +232,7 @@ target_openssl()
|
|||
target_bullet()
|
||||
target_opengl()
|
||||
add_crashpad()
|
||||
target_breakpad()
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
|
72
interface/src/Breakpad.cpp
Normal file
72
interface/src/Breakpad.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// Breakpad.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on 06/06/18
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Crashpad.h"
|
||||
|
||||
#if defined(HAS_BREAKPAD)
|
||||
#include <QDebug>
|
||||
|
||||
#include <common/linux/google_crashdump_uploader.h>
|
||||
#include <client/linux/handler/exception_handler.h>
|
||||
#include <client/linux/handler/minidump_descriptor.h>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtAndroidExtras/QAndroidJniObject>
|
||||
#include <QMap>
|
||||
#include <SettingHelpers.h>
|
||||
#include <mutex>
|
||||
|
||||
google_breakpad::ExceptionHandler *gBreakpadHandler;
|
||||
|
||||
std::mutex annotationMutex;
|
||||
QMap<QString, QString> annotations;
|
||||
|
||||
static bool breakpad_dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
QString obbDir() {
|
||||
QAndroidJniObject mediaDir = QAndroidJniObject::callStaticObjectMethod("android/os/Environment", "getExternalStorageDirectory", "()Ljava/io/File;");
|
||||
QAndroidJniObject mediaPath = mediaDir.callObjectMethod( "getAbsolutePath", "()Ljava/lang/String;" );
|
||||
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
|
||||
QAndroidJniObject package = activity.callObjectMethod("getPackageName", "()Ljava/lang/String;");
|
||||
QString dataAbsPath = mediaPath.toString()+"/Android/obb/" + package.toString();
|
||||
return dataAbsPath;
|
||||
}
|
||||
|
||||
bool startCrashHandler() {
|
||||
|
||||
gBreakpadHandler = new google_breakpad::ExceptionHandler(
|
||||
google_breakpad::MinidumpDescriptor(obbDir().toStdString()),
|
||||
nullptr, breakpad_dumpCallback, nullptr, true, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setCrashAnnotation(std::string name, std::string value) {
|
||||
std::lock_guard<std::mutex> guard(annotationMutex);
|
||||
QString qName = QString::fromStdString(name);
|
||||
QString qValue = QString::fromStdString(value);
|
||||
if(!annotations.contains(qName)) {
|
||||
annotations.insert(qName, qValue);
|
||||
} else {
|
||||
annotations[qName] = qValue;
|
||||
}
|
||||
|
||||
QSettings settings(obbDir() + "/annotations.json", JSON_FORMAT);
|
||||
settings.clear();
|
||||
settings.beginGroup("Annotations");
|
||||
for(auto k : annotations.keys()) {
|
||||
settings.setValue(k, annotations.value(k));
|
||||
}
|
||||
settings.endGroup();
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
#endif
|
20
interface/src/Breakpad.h
Normal file
20
interface/src/Breakpad.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Breakpad.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on 06/06/18
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Breakpad_h
|
||||
#define hifi_Breakpad_h
|
||||
|
||||
#include <string>
|
||||
|
||||
bool startCrashHandler();
|
||||
void setCrashAnnotation(std::string name, std::string value);
|
||||
|
||||
#endif // hifi_Crashpad_h
|
|
@ -114,7 +114,7 @@ void setCrashAnnotation(std::string name, std::string value) {
|
|||
crashpadAnnotations->SetKeyValue(name, value);
|
||||
}
|
||||
|
||||
#else
|
||||
#elif !defined(HAS_BREAKPAD)
|
||||
|
||||
bool startCrashHandler() {
|
||||
qDebug() << "No crash handler available.";
|
||||
|
|
Loading…
Reference in a new issue