Google Breakpad Android

开发过程中,最担心的问题就是程序崩溃,而且还不知道崩溃的原因,现在使用Google Breakpad来跟踪崩溃的位置,非常方便

由于目前使用Mac系统开发,Google Breadpad处理Android崩溃日志时需要Linux环境,借助vagrant可以非常方便地在Mac使用Ubuntu环境

有了vagrant以后就方便了

$ varant ssh
$ cd /vagrant
$ sudo apt-get update
$ sudo apt-get install build-essential
$ svn checkout http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad-read-only
$ cd google-breakpad-read-only
$ ./configure
$ make

这样就编译好了dump_syms与minidump_stackwalk工具,分析日志时需要

接下来就是整合breakpad_client.a静态库

我这里是与Cocos2d-x进行整合的,把google-breakpad-read-only目录拷贝到Cocos2d-x根目录,修改游戏工程的Android.mk文件,添加

LOCAL_STATIC_LIBRARIES += breakpad_client

$(call import-module,google-breakpad-read-only/android/google_breakpad)

修改jni/src/main.cpp,添加

#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"

bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
                  void* context,
                  bool succeeded) {
  LOGD("Dump path: %s\n", descriptor.path());
  return succeeded;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JniHelper::setJavaVM(vm);
 	
 	// 这里是定义dump文件的保存位置,保存至sd卡根目录
    google_breakpad::MinidumpDescriptor descriptor("/sdcard");
    google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, NULL, true, -1);

    return JNI_VERSION_1_4;
}

然后编译,在android工程的根目录下找到obj/local/armeabi/libxxx.so,把这个so复制到vagrant创建的ubuntu虚拟机根目录

回到ubuntu环境,生成sym文件

$ ./google-breakpad-read-only/src/tools/linux/dump_syms/dump_syms libxxx.so > libxxx.so.sym

查看libxxx.so.sym文件内容,头部会有,EB0351B143DA42A6D55FA6EA358B49D50不一样

MODULE Linux arm EB0351B143DA42A6D55FA6EA358B49D50 libxxx.so

接着执行

$ mkdir -p symbols/libxxx.so/EB0351B143DA42A6D55FA6EA358B49D50/
$ mv libxxx.so.sym symbols/libxxx.so/EB0351B143DA42A6D55FA6EA358B49D50/

当游戏在运行过程中崩溃了就会在sd卡根目录创建xxxx-xxxx-xxxxx-xxxx.dmp的文件,把这个文件复制到symbols同级目录,执行

$ ./google-breakpad-read-only/src/processor/minidump_stackwalk xxxx-xxxx-xxxxx-xxxx.dmp symbols > crashed.log

打开crashed.log就会发现类似

Thread 0 (crashed)
 0  libxxx.so!Crash [xxxxx.cpp : 28 + 0x4]

就是程序崩溃的位置,具体到xxxxx.cpp这个文件的28行

more: https://code.google.com/p/google-breakpad/source/browse/trunk/README.ANDROID

StormLib

创建mpq文件

HANDLE hMpq = NULL;
DWORD dwCreateFlags = MPQ_CREATE_ARCHIVE_V4;
TCHAR szMpqName[MAX_PATH] = "/Users/linguofeng/test/stormlib/new.mpq";
DWORD dwMaxFileCount = 1;

if (!SFileCreateArchive(szMpqName, dwCreateFlags, dwMaxFileCount, &hMpq)) {
    nError = GetLastError();
}

SFileCloseArchive(hMpq);

添加文件

if (!SFileAddFileEx(hMpq, "/Users/linguofeng/test/main.c", "main.c", MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED, MPQ_COMPRESSION_ZLIB, MPQ_COMPRESSION_NEXT_SAME))
{
    nError = GetLastError();
}

if (nError != ERROR_SUCCESS)
{
    return nError;
}

读取文件

HANDLE hFile = NULL;
TCHAR szArchivedFile[MAX_PATH] = "main.c";
if(!SFileOpenFileEx(hMpq, szArchivedFile, 0, &hFile))
{
    nError = GetLastError();
}

if (nError != ERROR_SUCCESS)
{
    return nError;
}

LPBYTE pbFileData = NULL;
DWORD dwFileSizeLo = 0;
DWORD dwBytes = 0;

// 获取文件的大小
dwFileSizeLo = SFileGetFileSize(hFile, NULL);
// 申请文件大小的内存
pbFileData = STORM_ALLOC(BYTE, dwFileSizeLo);
// 初始化内存
memset(pbFileData, 0, dwFileSizeLo);
// 读取文件内容
SFileReadFile(hFile, pbFileData, dwFileSizeLo, &dwBytes, NULL);
// 关闭文件操作柄
SFileCloseFile(hFile);

printf("文件内容:\n%s\n文件长度:%d\n", pbFileData, dwBytes);
STORM_FREE(pbFileData);

patch的使用

主文件的listfile

main.cpp

patch文件的listfile

main.cpp
SFileOpenPatchArchive(hMpq, "patch.mpq", "", 0)   // szPatchPathPrefix为NULL时,默认值为base
SFileIsPatchedArchive(hMpq)

Cocos2d-x Curl Gzip

HttpClient.cpp中的configureCURL里加入

code = curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip");
if (code != CURLE_OK) {
    return false;
}

关键字:curl, CURLOPT_ACCEPT_ENCODING, gzip

Cocos2d-x And Gradle

安装Gradle

$ brew update
$ brew install gradle

创建化gradle

$ cd $COCOS2DX-ROOT
$ gradle init

修改build.gradle,替换成

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}

修改settings.gradle,替换成/p>

include ':cocos2d:platform:android:java'
include ':projects:xxxx:proj.android'

创建build.gradle,保存至cocos2dx/platform/android/java里

apply plugin: 'android-library'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.3"

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
    }
}

创建build.gradle保存至项目中

apply plugin: 'android'

repositories {
    mavenCentral()
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    compile fileTree(dir: "libs/armeabi", include: '*/so')
    compile project(':cocos2dx:platform:android:java')
}

// 编译so动态库
task ndkBuild(type: Exec) {
    commandLine './build_native.sh', 'NDK_DEBUG=1', 'NDK_APPLICATION_MK=jni/Application.mk', '-j4'
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.3"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 19
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }
    }
}

编译

$ gradle ndkBuild
$ gradle installDebug
</section>

Android Wear

Android出智能手表平台了,然后就去申请了个测试,很简单,在线报名,然后会回复一个邮件,点击邮件中的链接去play上下载app

具体步骤看官网介绍

1. Open the Android Wear Preview app. You should see a notice that the app is currently not enabled as a notification listener. Tap the message to open the system settings, then select Android Wear Preview to grant it notification access. 2. Connect your device to your development machine over USB. Be sure that no other Android devices are connected to the machine. 3. Ensure that the Android Wear emulator (created in the previous section) is running. The emulator should show the time and an icon that indicates no device is connected. 4. Open a command line terminal, navigate to your Android SDK's platform-tools/ directory, then execute: adb -d forward tcp:5601 tcp:5601 5. Return to the Android Wear Preview app. It should now indicate that it is connected to the emulator. The Android Wear emulator should now show the 'g' orb icon, indicating that is is connected to your device.

大概意思就是启动Android Wear模拟器,打开Android Wear Preview应用,打开权限,usb连接电脑,使用adb -d forward tcp:5601 tcp:5601命令,然后手机收到通知会同步推到Android Wear模拟器上。

还有一个开发工具包,明天有空自己写个app玩一下。

see: http://developer.android.com/wear/preview/start.html