Login or Sign up

All Blogs

These are blog posts from everyone:

Android NDK: JNI 调试

和其他开发套件一样,Android NDK 也提供了一些手段来帮助调试编写的 JNI。主要手段包括: log --- 在 C/C++ 代码里,可以直接调用 Android 底层的 _androidlog_print,它的作用跟 SDK 的 Log 完全一样,就是 Jave 里 Log 的底层实现(我的猜想 ^_^). #include <android/log.h> #define TAG "your tag" #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, TAG, _VAARGS)) #define LOGW(...) ((void)android_log_print(ANDROID_LOG_WARN, TAG, _VAARGS__)) gdb --- 跟所有 Unix like 的环境一样,也可以用使用 gdb 来调试。Android NDK 提供了一个命令 ndk-gdb 便于 gdb 的使用。ndk-gdb 是一个 Shell 脚本,它会做一些环境的检查适配,帮我们在目标机上(Android 手机或者模拟器)启动 gdbserver,然后在 PC 上启动 gdb 并连接到 gdbserver,跟通用的 gdb 没有差别。 为了使用 ndk-gdb,有几个地方需要注意: 1. 需要在 AndroidManifest.xml 里面给 application 加上属性 android:debuggable="true",充许调式 2. JNI 的 Android.mk 编译选项要加调试信息 LOCAL_CFLAGS := -ggdb 3. ndk-build 命令加参数 NDK_DEBUG=1 准备好 apk 后,启动 gdb $ /cygdrive/c/Android/android-ndk-r6b/ndk-gdb --adb=/cygdrive/c/Android/android-sdk/platform-tools/adb.exe -s 0123456789ABCDEF --start 相关blog用 NDK 编写 JNI

kernel.org Down!

kernel.org 宕机好多天了,到现在还没恢复。网上有人说被攻击者用 Phalanx self-injecting rootkit 取得了 root 权限,感觉这个问题有点挑战,收了一篇文章留着研究一下。

Ubuntu 10.04 Xen PVM Template

不想自己做 PVM image,google 好几次才找到一个别人做好的,共享一下: Isaac Zarb博客 共享了一个,可以从这里下载。 用户: root 密码: password

Android NDK: 用 NDK 编写 JNI

Android NDK: 用 NDK 编写 JNI ============================ 除了SDK,Android 还提供了一套可以直接用 C/C++ 编程的 NDK。这里将会介绍如何用 NDK 编写 JNI。 Google Android 文档里面有一个简单的 NDK 教程,大致的过程是: 1. 把你的C/C++代码放到路径 &lt;project&gt;/jni/... 2. 为 NDK 编译系统创建 &lt;project&gt;jni/Android.mk 3. 可选:创建 &lt;project&gt;/jni/Application.mk 4. 用 ndk-build 编译你的工程: cd &lt;project&gt; &lt;ndk&gt;/ndk-build 5. 编译工具会把 stripped, shared libraries 放到应用工程的正确路径。最后,用 SDK 编译你的应用,SDK 编译工具会把 shared libraries 打包到应用的 .apk 文件里。 Google 这个教程描述得非常简单,这里结合一个具体的工程讨论一些细节。 C++ 代码 -------- 如果 JNI 是用 C++ 编写的,需要声明 extern "C"。 #ifdef __cplusplus extern "C" { #endif // JNI code here... #ifdef __cplusplus } #endif 不然运行时会报 java.lang.UnsatisfiedLinkError 异常。 在 C++ 里面,JNIEnv* 的用法跟 C 不一样: env->NewStringUTF("Hello from JNI !"); Android.mk ---------- 我的工程的 Android.mk: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CPPFLAGS += -fexceptions -frtti -DTIXML_USE_TICPP # enable exception/rtti, 自定义宏 LOCAL_MODULE := xmpp2ber # 目标库 LOCAL_SRC_FILES := xmpp2ber.cpp ticpp.cpp tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp LOCAL_CFLAGS := -ggdb # 包含 gdb 调试信息,发行版本需要关掉 include $(BUILD_SHARED_LIBRARY) Application.mk -------------- 指定要使用静态 gnu stl 库: APP_STL := gnustl_static ndk-build --------- NDK 编译时,为了看到详细的编译过程,可以加开关: ndk-build V=1 -B 如果想编译 DEBUG ...

jabberd2: c2s 模块分析

基于jabberd-2.2.9做的分析,客户端用的 Psi v0.14。 网上有一些分析 jabberd2 结构的文章,具体在这就不细说。 因为我们项目目前需要修改 C2S 跟客户端的通讯协议,直接进入主题,分析从客户端收到一个包,并触发event_PACKET: 调用栈: #0 c2sclient_sx_callback (s=0x8098398, e=event_PACKET, data=0x80a20a0, arg=0x8099768) at c2s.c:251 #1 0x0805b236 in _sxevent (file=0x806ec3d "io.c", line=156, s=0x8098398, e=event_PACKET, data=0x80a20a0) at sx.c:328 #2 0x08059c07 in sxprocess_read (s=0x8098398, buf=0x80a18c0) at io.c:156 #3 0x0805a2c7 in sx_can_read (s=0x8098398) at io.c:243 #4 0x080516fc in c2sclient_mio_callback (m=0x807b8e0, a=action_READ, fd=0x8099750, data=0x0, arg=0x8099768) at c2s.c:536 #5 0x08062c1e in miorun (m=0x807b8e0, timeout=5) at mio_impl.h:261 #6 0x08056961 in main (argc=3, argv=0xbfffea04) at main.c:732 可以看出来,mio 模块收到数据后,转给 sx,sx 再调用回调 c2sclient_sx_callback。 <To Be Continue>

Android Camera Preview

最近做一个 Android Camera 的实验,按照 SDK 的实例写了一个APP,Camera 怎么看都像翻转了90度。经过尝试,在 AndroidMenifest.xml 修改了一下 Activity 的属性,添加 android:screenOrientation="landscape" 即可解决问题。 原来 Android Camera Preview 要强制设成 landscape 模式,文档里面没有强调。

切换到 EXT4

这几天在考虑存储海量图片的问题,想到 EXT4 加入了 htree 为目录做索引,性能应该有很明显的提升。 root@vps3:~/haohai/test_images# cat /proc/cpuinfo processor : 0 vendor_id : AuthenticAMD cpu family : 16 model : 9 model name : AMD Opteron(tm) Processor 6128 stepping : 1 cpu MHz : 2000.000 cache size : 512 KB fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 5 wp : yes flags : fpu de tsc msr pae cx8 cmov pat clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt 3dnowext 3dnow constant_tsc up nonstop_tsc amd_dcm pni popcnt hypervisor cmp_legacy extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch nodeid_msr bogomips : 4000.00 clflush size : 64 cache_alignment : 64 address sizes : 48 bits physical, 48 bits virtual power management: ts ttp tm stc 100mhzsteps hwpstate root@vps3:~/haohai/test_images# cat /proc/meminfo MemTotal: 248828 kB MemFree: 149548 kB Buffers: 19496 kB Cached: 11380 kB SwapCached: 10480 kB Active: 3892 kB ...

ARM C 调用传参(Calling Conversation)

ARM C 调用传参(Calling Conversation) ==================================== 了解 C 函数的调用传参方式, 是阅读汇编语言的一个很重要的基本知识,对分析 core dump 有直接的帮助。 这里通过比较 ARM EABI 和常用的 x86 C 调用传参方式的差别, 进一步理解 ARM C 的传参方式。 一个简单的 C 程序: $ cat main.c int a(int p1, int p2, int p3, int p4, int p5, int p6) { return p1+p2+p3+p4+p5+p6; } int main(int argc, char *argv[]) { printf("p1=%d,p2=%d,p3=%d,p4=%d,p5=%d,p6=%d", 1, 2, 3, 4, 5, 6); return a(1,2,3,4,5,6); } x86 --- 在 x86 平台上,所有的 C 参数按照最先一个参数最先入栈 (高地址) 的顺序全部压入栈。 $ objdump -d main_x86 ... 080483c4 <a>: 80483c4: 55 push %ebp 80483c5: 89 e5 mov %esp,%ebp 80483c7: 8b 45 0c mov 0xc(%ebp),%eax 80483ca: 8b 55 08 mov 0x8(%ebp),%edx 80483cd: 8d 04 02 lea (%edx,%eax,1),%eax 80483d0: 03 45 10 add 0x10(%ebp),%eax 80483d3: 03 45 14 add 0x14(%ebp),%eax 80483d6: 03 45 18 add 0x18(%ebp),%eax 80483d9: 03 45 1c add 0x1c(%ebp),%eax 80483dc: 5d pop %ebp 80483dd: c3 ret 080483de <main>: 80483de: 55 push %ebp 80483df: 89 e5 mov %esp,%ebp 80483e1: 83 e4 ...

Build Android Emulator on Ubuntu 10.10

成功把 G1 升级到 android 2.2!

之前的版本是 hiapk 1.7 的,recovery, radio, spl, firmware 全部需要升级。 按照 cyanogenmod 提供的教程: http://wiki.cyanogenmod.com/index.php?title=Dream:Installing_CyanogenMod_5%2B

隐私之争,满地鸡毛

口水 ---- 这两天 360 和 QQ 围绕用户隐私问题展开了一系列口水战,本来我是不太关注,只是偶尔在休息时看看新闻报道。直到昨天对骂继续升级,以至于开始人身攻击,让我开始有些惊诧,也引起了我的注意。昨天特意去这两家的网站看了看,骂街的意味相当浓!但是有意义的信息却并不多,QQ 并没明确的说有没有窥探用户隐私,而是一味攻击 360,而 360 的申明一打开就看到“腾讯CEO马化腾身价近300亿仍在领取政府发放的住房补贴”,看来都是来者不善。 真相 ---- 360 和 QQ 似乎更热衷于互相攻击,而并不在意用户的感受。而我既然无意中被引来围观这场骂战,并且不幸的在自己电脑上都有装过 360 和 QQ,所以决定自己动手弄清真相。 QQ 是否有可疑文件访问? ---------------------- 骂战的最近一个由头应该就是从 360 指责 QQ 窥视用户隐私开始的,我的电脑上也装了 QQ,隐私是否被 QQ 窥视确实是个严重的问题。试了一下 360 的隐私保护器,QQ2008 被报告扫描过 C:\WINDOWS 和 C:\Program Files 下的文件,行迹可疑。但是鉴于 360 和 QQ 正在打口水战,360 的报告自然令人怀疑。 看来需要自己动手寻找真相了。 QQ 在 Windows 平台上要扫描文件显然需要调用系统接口,在 Linux 平台上,分析程序调用了哪些 API,包括调用时的参数,用 strace 很方便,但是在 Windows 平台上没有类似的工具。于是我想到了 wine。在 Linux 上用 wine 来运行 QQ,然后利用 wine 的调试功能查看所有文件相关的调用。 环境: $ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=10.04 DISTRIB_CODENAME=lucid DISTRIB_DESCRIPTION="Ubuntu 10.04 LTS" $ wine --version wine-1.1.42 QQ 用的 QQ2008,从 http://download.tech.qq.com/soft/17/21/42698/index.shtml 下载。 至于 wine 怎么安装可以 google 一下 "ubuntu 10.04 wine qq",我参考了: http://mucid.me/2010/05/391.html 用 wine 启动 QQ,并把所有文件操作的调试信息保存到一个记录文件: $ WINEDEBUG=+file wine "c:/Program Files/Tencent/QQ/QQ.exe" > /data/nua/qq2008_file_log 2>&1 替换掉 QQ 号码,最后得到 qq2008_file_log_without_id 用于分析。 让 QQ 运行 10 分钟左右,期间除了用鼠标停靠在好友头像上看好友信息外,不做类似收发文件、导出之类的操作。 ### 结果分析 #### 可疑的 FindFirstFileExW 调用 根据 MSDN(http://msdn.microsoft.com/en-us/library/aa364419(VS.85).aspx?1288372964),FindFirstFileExW 是为扫描文件准备一个句柄,然后调用 FindNextFileW 遍历文件。通常来说,如果一个软件遍历它的安装和配置目录之外的目录,其行为和动机就很可疑。从日志来看,QQ 扫描了包括系统目录、默认的软件安装目录、开始菜单、桌面等目录,而这些目录跟他们在回应 360 的文章(http://tech.qq.com/a/20100930/000369.htm)中提到的_“当用QQ传文件、另存为、截图时都会出现保存文件的系统对话框,如果选择存在桌面上,那么对话框会显示桌面上应用程序的图标,此时系统会调用PrivateExtraIconW()以及CreateIconFromResourceEx()函数从exe文件里面读取图标来显示,而这两个函数内部会调用CreateFileW()”_显然有出入。该文中并没有提到 FindFirstFileExW 的使用场景和目的。当然,看起来 360 的隐私保护器也没有监视这个 API。 运行 grep FindFirstFileExW qq2008_file_log_without_id | grep -v "Tencent" 得到的部分结果: trace:file:FindFirstFileExW L"C:\windows\system32" 0 0x151c96c 0 (nil) 0 ...

Qubes: 基于 Xen 的安全桌面操作系统

今天在 Xen 社区发现了一个项目 Qubes OS 看了一下这个 OS 的框架文档 (本地镜像), 基本原理是把不同领域的任务放在不同的 domain 执行, 利用 Xen 的 hypervisor 更好的隔离任务. 通过传统的 OS 暴露的漏洞被攻击后, 几乎整个系统都后被攻击者控制. 如果把一个服务单独放在一个 VM 里, 即使该服务被攻击, 也不会影响运行在其他 VM 上的服务. 这应该是安全领域的一个方向: 更好的任务隔离.

加快 SSH

平常工作时, 写代码的机器和测试机器往往不是同一台, 常用 SSH 来同步数据和发送测试命令. 所以对 SSH 的速度要求比较高. 今天查了一下 SSH FAQ, 修改了一下 SSH 服务器的配置, 速度有明显的提高! 原来的速度 ---------- $ time scp vdiskman.py root@linux3:~/ vdiskman.py 100% 9298 9.1KB/s 00:00 real 0m30.969s user 0m0.032s sys 0m0.004s 修改 SSH 服务器配置, 关闭 DNS ----------------------------- [root@linux3 ~]# grep UseDNS /etc/ssh/sshd_config UseDNS no 现在的速度 ---------- $ time scp vdiskman.py root@linux3:~/ vdiskman.py 100% 9298 9.1KB/s 00:00 real 0m0.209s user 0m0.028s sys 0m0.008s 快100多倍! ---------- 可以看到用时从 30.969s 减少到 0.209s! 对于我这种经常几分钟就需要运行 scp/ssh 命令几次的情况, 生活变得轻松很多!

VMware tools 下载和安装

VMware tools 的下载地址在 VMware 官方网站没有提供,以下是挖掘出来的地址。 http://downloads.vmware.com/d/info/desktop_downloads/vmware_player/3_0 http://softwareupdate.vmware.com/cds/index.xml http://softwareupdate.vmware.com/cds/vmw-desktop/player-windows.xml VMware Tools for FreeBSD http://softwareupdate.vmware.com/cds/vmw-desktop/player/3.0.1/227600/windows/tools-freebsd-8.1.4.exe.tar VMware Tools for Linux http://softwareupdate.vmware.com/cds/vmw-desktop/player/3.0.1/227600/windows/tools-linux-8.1.4.exe.tar VMware Tools for Netware http://softwareupdate.vmware.com/cds/vmw-desktop/player/3.0.1/227600/windows/tools-netware-8.1.4.exe.tar VMware Tools for Solaris http://softwareupdate.vmware.com/cds/vmw-desktop/player/3.0.1/227600/windows/tools-solaris-8.1.4.exe.tar VMware Tools for Windows 2000 and later http://softwareupdate.vmware.com/cds/vmw-desktop/player/3.0.1/227600/windows/tools-windows-8.1.4.exe.tar VMware Tools for Windows 95, 98, Me and NT http://softwareupdate.vmware.com/cds/vmw-desktop/player/3.0.1/227600/windows/tools-winPre2k-8.1.4.exe.tar 下载完成后,解开压缩包,在命令行运行: Windows: E:\VMware\VMware Player\vmware-tools>tools-linux-8.1.4.exe /s/v/qn

像 VIM 一样操作 Firefox

使用 VIM 多年,非常喜欢它的全键盘操作方式,时常想要是 Firefox 也支持全键盘操作,企不是方便很多。 今天闲来找到了一个 vimperator,一个 Firefox 的插件。安装的这个插件后,常用的 VIM 操作几乎都支持了。另外,vimperator 本身还支持用 Javascript 编写的插件,扩展其功能也很方便。 就像 VIM ,很多人 对Vimperator 的默认设置可能不太习惯,可以通过 Vimperator 的配置文件来修改。在 Windows 平台上是 C:\Documents and Settings\&lt;user>\_vimperatorrc,在 Linux 平台上是 ~/.vimperatorrc。 以下是我在使用的配置文件: "Turn the menu and toolbar on. :set guioptions+=mT "Turn off the show tabs by default. :set showtabline=1 "Turn session tracking off. :set! browser.startup.page=1 "Allow user to click in address bar. :set! browser.urlbar.clickSelectsAll=true :set! browser.urlbar.doubleClickSelectsAll=true "Map Ctrl + n for new windows " :map <C-n> <C-v><C-n> "Map Ctrl + t for new tabs :map <C-t> :tabopen<Enter> "Map paste operation normally. :noremap <C-c> <C-v><C-c> :imap <C-v> <C-v> 详细的配置可以参考 Vimperator 的手册。 另外,这里有个图形化(英文)的常用键说明。

Android:用定时器 timer 刷新界面

在 Android 平台上,界面元素不能在定时器的响应函数里刷新。 以下这段代码中,mButton 的文本并不变化。 public class AndroidTimerDemo extends Activity { private Button mButton; private Timer mTimer; private TimerTask mTimerTask; /* Called when the activity is first created. / @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mButton = (Button) findViewById(R.id.Button01); mTimer = new Timer(); mTimerTask = new TimerTask() { @Override public void run() { Log.d("AndroidTimerDemo", "timer"); Calendar cal = Calendar.getInstance(); mButton.setText(cal.toString()); } }; mTimer.schedule(mTimerTask, 1000, 1000); } } 在 Android 平台上,UI 单元必须在 Activity 的 context 里刷新。 为了达到想要的效果,可以使用 Message Handler。在定时器响应函数里发送条消息,在 Activity 里响应消息并更新文本。 public class AndroidTimerDemo extends Activity { protected static final int UPDATE_TEXT = 0; private Button mButton; private Timer mTimer; private TimerTask mTimerTask; private Handler mHandler; /* Called when the activity is first created. / @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mButton = (Button) findViewById(R.id.Button01); mTimer = new Timer(); mHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case UPDATE_TEXT: Calendar cal = Calendar.getInstance(); ...

Android 性能分析

找到软件系统里最费时的代码,是提高系统性能的一个直接方法。 目前各种语言和平台基本上都有相应的工具做这种分析,Android 上也提供了一个 Traceview 工具。 Traceview 工作方式 ------------------- 要使用 Traceview,首先要生成 trace 文件。在需要跟踪的代码开始前调用 Debug. startMethodTracing(),在结束处调用 Debug.stopMethodTracing()。通常可以在 onCreate() 中调用 startMethodTracing(),在 onDestroy() 中调用 stopMethodTracing()。例如: // start tracing to "/sdcard/babytracker.trace" Debug.startMethodTracing("babytracker"); // ... // stop tracing Debug.stopMethodTracing(); 如果是在模拟器上生成 trace 文件,需要先创建一个 sd 文件。 生成 trace 文件后,把文件导出,然后即可用 traceview 工具查看。 其中 Inclusive time 表示函数和被它调用的函数总用时,Exclusive time 表示函数本身用时。 在 startMethodTracing() 调用后,程序的性能会降低,所以不要在最后发行版里使用。不过可以分析出函数的相对用时。

在 Eclipse 中浏览 Android 的源代码

最近在做另一个 Android 项目,经常需要看开发文档。本来 Android 源代码里有文档,但是 Android SDK 自带的库不能指定源代码路径。 当然,先 google 一下。找到了 Eric Burke 的一篇博客。他通过 Android 的源代码,找到了 android.jar 的源码路径,即sdk_dir/sources,只需要把 Android 源码放到该路径,再刷新一下工程,可以直接浏览了! 不过有个问题,Android 的源代码散落在不同的目前,想把它们复制到一个目录不容易。 Dr. Michael Forster博客给出了一个 Python 脚本来解决这个问题。

Django model class 国际化

Django model 中定义的表名默认显示为英文, 可以通过一个子类 Meta 来控制. 例如: class Bank(models.Model): name = models.CharField(max_length=20, unique=True) class Meta: verbose_name = _("bank") verbose_name_plural = _("banks") Django 文档中的相关描述 ------------------------ verbose_name Options.verbose_name A human-readable name for the object, singular: verbose_name = "pizza" If this isn't given, Django will use a munged version of the class name: CamelCase becomes camel case. verbose_name_plural Options.verbose_name_plural The plural name for the object: verbose_name_plural = "stories" If this isn't given, Django will use verbose_name + "s".

VPN 与本地网共存

本地网和 VPN 怎么共存 ---------------------- 由于很多原因, 经常会使用 VPN. VPN 有很多优点, 比如安全, 比如可以避开一些不必要的麻烦. 不过 VPN 也带来一些新麻烦, 例如, 访问一些本地服务器速度往往会慢很多. 如何才能让部分数据包走 VPN, 部分走本地网呢? 路由表 ------- 经过分析, 发现一般 VPN 客户端在 VPN 连接建立后, 会修改路由表添加一个默认路由, 让所有的数据包都走 VPN. 如果对路由表进行相应调整, 应该可以达到目的. 实例 ------ 连接 VPN 前的路由表 $ route print ... Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 192.168.1.1 192.168.1.4 1 127.0.0.0 255.0.0.0 127.0.0.1 127.0.0.1 1 169.254.0.0 255.255.0.0 192.168.235.1 192.168.235.1 30 192.168.1.0 255.255.255.0 192.168.1.4 192.168.1.4 20 192.168.1.4 255.255.255.255 127.0.0.1 127.0.0.1 20 192.168.1.255 255.255.255.255 192.168.1.4 192.168.1.4 20 192.168.20.0 255.255.255.0 192.168.20.1 192.168.20.1 20 192.168.20.1 255.255.255.255 127.0.0.1 127.0.0.1 20 192.168.20.255 255.255.255.255 192.168.20.1 192.168.20.1 20 192.168.235.0 255.255.255.0 192.168.235.1 192.168.235.1 20 192.168.235.1 255.255.255.255 127.0.0.1 127.0.0.1 20 192.168.235.255 255.255.255.255 192.168.235.1 192.168.235.1 20 224.0.0.0 240.0.0.0 192.168.1.4 192.168.1.4 20 224.0.0.0 240.0.0.0 192.168.20.1 192.168.20.1 20 224.0.0.0 240.0.0.0 192.168.235.1 192.168.235.1 20 255.255.255.255 255.255.255.255 192.168.1.4 192.168.1.4 1 255.255.255.255 255.255.255.255 192.168.20.1 192.168.20.1 1 255.255.255.255 255.255.255.255 192.168.235.1 6 1 255.255.255.255 255.255.255.255 192.168.235.1 4 1 255.255.255.255 255.255.255.255 192.168.235.1 192.168.235.1 1 255.255.255.255 ...