December 18
浅析android下如何通过jni监控wifi(三)
jni
=>runDhcp
=>android_net_utils_runDhcp
libs/netutils/dhcp_utils.c
=>dhcp_do_request
=>
static const char DAEMON_NAME[] = "dhcpcd";
static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
const char *ctrl_prop = "ctl.start";
const char *desired_status = "running";
snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
property_set(result_prop_name, "");//设置dhcp.eth0.result="";等到成功完成dhcp之后,
property_set(ctrl_prop, DAEMON_NAME);//向名字为dhcpcd的service,发送"ctrl.start"启动命令字,该service在init.rc中
//init.rc中dhcpcd服务进程命令字
//service dhcpcd /system/bin/dhcpcd eth0
// disabled
// oneshot
wait_for_property(DAEMON_PROP_NAME, desired_status, 10);
//init.c=>init进程
//=>handle_property_set_fd因为是"ctrl.start"命令字,所以调用handle_control_message处理控制信息
//=>handle_control_message
//=>msg_start
//=>
// struct service *svc = service_find_by_name(name);
// service_start(svc);//启动svc,即执行:/system/bin/dhcpcd eth0
//=>service_start
//=>pid = fork();
// if(pid == 0)execve(svc->args[0], (char**) svc->args, (char**) ENV);子进程执行execve运行/system/bin/dhcpcd,参数为eth0
//=>否则父进程,即init进程将
//=>notify_service_state(svc->name, "running");设置该svc的状态prop
// snprintf(pname, sizeof(pname), "init.svc.%s", name);
// property_set(pname, state);//所以这样上面wait_for_property(DAEMON_PROP_NAME, desired_status, 10);也才能够正常pass[luther.gliethttp].
wait_for_property(result_prop_name, NULL, 15);//等待dhcp.eth0.result=非空
=============================================================================================================
system/extra/dhcpcd-4.0.0-beta9/dhcpcd.c
dhcpcd
=>main
# define SYSCONFDIR "/system/etc/dhcpcd"
#define PACKAGE "dhcpcd"
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
# define LIBEXECDIR "/system/etc/dhcpcd"
# define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
=>strlcpy(options->script, SCRIPT, sizeof(options->script));//默认的options->script="/system/etc/dhcpcd/dhcpcd-run-hooks"
=>f = fopen(cf ? cf : CONFIG, "r");//如果没有指定.conf文件,那么使用默认.conf文件
=>parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件
=>parse_option
=>如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节
=>那么执行strlcpy(options->script, oarg, sizeof(options->script));直接拷贝
/*
{"script", required_argument, NULL, 'c'},
{"option", required_argument, NULL, 'o'},
"/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下:
...
option domain_name_servers, domain_name, domain_search, host_name
...
*/
=>dhcp_run
=>handle_dhcp_packet
=>handle_dhcp
=>bind_dhcp
reason = "TIMEOUT";reason = "BOUND";reason = "REBIND";reason = "RENEW";
system/extra/dhcpcd-4.0.0-beta9/configure.c
=> configure(iface, reason, state->new, state->old, &state->lease, options, 1);
//如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本,
//执行setprop dhcp.${interface}.result "failed"或者
//执行setprop dhcp.${interface}.result "ok"
=>exec_script(options, iface->name, reason, NULL, old);
=>然后configure_env通过环境变量将reason传递到脚本中
int exec_script(const struct options *options, const char *iface, const char *reason,
const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
=>pid = fork();
=>if(pid == 0)execve(options->script, argv, env);//子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks"
//dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件
//我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下3个文件
//95-configured
//20-dns.conf
//01-test
=>父进程返回while (waitpid(pid, &status, 0) == -1)等待子进程脚本执行完成
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/20-dns.conf
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/95-configured
...
setprop dhcp.${interface}.ipaddress "${new_ip_address}"
setprop dhcp.${interface}.result "ok"//设置属性为ok
setprop dhcp.${interface}.result "failed"
...
=============================================================================================================
inet_init、tcp_prot
sock->ops->sendmsg(iocb, sock, msg, size);
=>inetsw_array[]
=>inet_stream_ops
=>tcp_sendmsg
=============================================================================================================
wpa_cli.c
=>main
=>wpa_cli_interactive
=>wpa_cli_recv_pending(monitor_conn, 0, 0);//阻塞等待wpa_supplicant发送数据过来
=>如果action_monitor为true,那么将执行一些简单加工操作,否则将直接将wpa_supplicant发过来的数据打印到console上[luther.gliethttp].
============================================================================================================= 2:28 PM | Add a comment | Permalink | Blog it | Android浅析android下如何通过jni监控wifi(二)
//剔除前导控制字符,将" - "后面的描述字符串作为真实数据,继续处理
...
if (event == STATE_CHANGE) {
handleSupplicantStateChange(eventData);
} else if (event == DRIVER_STATE) {
handleDriverEvent(eventData);
} else {
handleEvent(event, eventData);//对于CONNECTED和DISCONNECTED等netlink事件将执行此操作来处理[luther.gliethttp]
// If supplicant is gone, exit the thread
if (event == TERMINATING) {
break;
}
}
...
void handleEvent(int event, String remainder) {
switch (event) {
case DISCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
break;
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);//控制界面显示
break;
...
}
public class WifiStateTracker extends NetworkStateTracker {
...
public void startEventLoop() {
mWifiMonitor.startMonitoring();//启动上面的MonitorThread线程
}
...
}
java/services/com/android/server/WifiService.java
public class WifiService extends IWifiManager.Stub {
...
private boolean setWifiEnabledBlocking(boolean enable) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
...
if (enable) {
if (WifiNative.loadDriver()) {
Log.e(TAG, "Failed to load Wi-Fi driver.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
if (WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
Log.e(TAG, "Failed to start supplicant daemon.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
mWifiStateTracker.startEventLoop();
//启动MonitorThread线程,等待wpa_supplicant将netlink数据转发过来,然后根据netlink动作类型,进一步影响界面显示[luther.gliethttp].
}
...
}
java/android/android/net/wifi/WifiStateTracker.java
电源管理
private void handleConnectedState() {
...
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();//传递到下面的handleMessage方法
...
}
public void onChange(boolean selfChange) {
...
handleConnectedState();
...
}
public class WifiStateTracker extends NetworkStateTracker {
...
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SUPPLICANT_CONNECTION:
case EVENT_NETWORK_STATE_CHANGED:
handleConnectedState();//调用
...
private class DhcpHandler extends Handler {
private Handler mTarget;
public DhcpHandler(Looper looper, Handler target) {
super(looper);
mTarget = target;
}
public void handleMessage(Message msg) {
int event;
//private static final int DRIVER_POWER_MODE_AUTO = 0;
//private static final int DRIVER_POWER_MODE_ACTIVE = 1;
switch (msg.what) {
case EVENT_DHCP_START:
synchronized (this) {
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);//设置电源模式,调用android_net_wifi_setPowerModeCommand
}
Log.d(TAG, "DhcpHandler: DHCP request started");
//libs/android_runtime/android_net_NetUtils.cpp
//static JNINativeMethod gNetworkUtilMethods[] = {
//{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
// ...
//};
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {//执行dhcp申请ip地址操作
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
if (LOCAL_LOGD) Log.v(TAG, "DhcpHandler: DHCP request succeeded");
} else {
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
Log.i(TAG, "DhcpHandler: DHCP request failed: " +
NetworkUtils.getDhcpError());
//如果dhcpcd分配ip失败,那么Message.obtain(mTarget, event).sendToTarget();将执行
//WifiNative.disconnectCommand();即:static JNINativeMethod gWifiMethods[] = {
//android_net_wifi_disconnectCommand发送"DISCONNECT"字符串[luther.gliethttp]
//然后在wpa_supplicant服务端执行wpa_supplicant_ctrl_iface_process
//wpa_supplicant_disassociate
}
synchronized (this) {
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_AUTO);
}
Message.obtain(mTarget, event).sendToTarget();
break;
}
}
}
...
/**
* Send the tracker a notification that a connection to the supplicant
* daemon has been established.
*/
//在上面的public class WifiMonitor=>ensureSupplicantConnection
//=>
//while (!supplicantConnected) {
// boolean connected;
//synchronized (mWifiStateTracker) {
//connected = WifiNative.connectToSupplicant();//如果没有连接成功,那么while循环尝试,直到尝试成功,或者定义了oneShot,仅一次尝试
//=>mWifiStateTracker.notifySupplicantConnection();//如果WifiNative.connectToSupplicant()成功,那么将执行
//mWifiStateTracker.notifySupplicantConnection();的调用.
void notifySupplicantConnection() {//向对象发送message
Message.obtain(this, EVENT_SUPPLICANT_CONNECTION).sendToTarget();
}
void notifyStateChange(SupplicantState newState) {
Message.obtain(this, EVENT_SUPPLICANT_STATE_CHANGED, newState).sendToTarget();
}
...
}
static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
{
char cmdstr[256];
sprintf(cmdstr, "DRIVER POWERMODE %d", mode);
return doBooleanCommand(cmdstr, "OK");
}
android_net_wifi_setPowerModeCommand
=>doBooleanCommand
=>doCommand
=>wifi_command
=>wifi_send_command
=>wpa_ctrl_request
=>send给wpa_supplicant
然后wpa_supplicant将做如下接收操作:
system/extra/wpa_supplicant/main.c
=>wpa_supplicant_add_iface
=>wpa_supplicant_init_iface2
=>wpa_supplicant_ctrl_iface_init
=>注册ctrl_conn控制端口和monitor_conn监听端口的处理函数
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);//ctrl_conn端口的handler处理函数
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);//monitor_conn端口的回调处理函数,处理netlink数据到所有monitor_conn监听端口
=>wpa_supplicant_ctrl_iface_receive//对于unix通信方式
=>wpa_supplicant_ctrl_iface_process
=>如果wpa_cli发送的是wpa_cli driver xxx形式的命令,那么调用这个函数
if (os_strncmp(buf, "DRIVER ", 7) == 0) {//掠过前7个,直接将命令传过去
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, reply_size);
=>wpa_supplicant_driver_cmd
=>wpa_drv_driver_cmd
=>自定义DRIVER扩展处理函数,所以对于java传递过来的power电源管理命令,wpa_drv_driver_cmd将收到"POWERMODE 0"或者"POWERMODE 1"字符串[luther.gliethttp]
=============================================================================================================
2:27 PM | Add a comment | Permalink | Blog it | Android浅析android下如何通过jni监控wifi(一)
浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制
=============================================================================================================
libs/android_runtime/android_net_wifi_Wifi.cpp
部分jni接口
static JNINativeMethod gWifiMethods[] = {
{ "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },
{ "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },//电源管理
{ "connectToSupplicant", "()Z", (void *)android_net_wifi_connectToSupplicant },
{ "waitForEvent", "()Ljava/lang/String;", (void*) android_net_wifi_waitForEvent },
{ "disconnectCommand", "()Z", (void *)android_net_wifi_disconnectCommand },
...
};
int register_android_net_wifi_WifiManager(JNIEnv* env)
{
...
return AndroidRuntime::registerNativeMethods(env,
WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));//登记jni
}
libs/android_runtime/AndroidRuntime.cpp
static const RegJNIRec gRegJNI[] = {
...
REG_JNI(register_android_net_wifi_WifiManager),
...
};
int AndroidRuntime::startReg(JNIEnv* env)
{
...
register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
...
}
AndroidRuntime::start
=>startReg(env)即调用方法int AndroidRuntime::startReg(JNIEnv* env)
=============================================================================================================
wifi_load_driver
wifi_start_supplicant
=>ensure_config_file_exists
//检查/data/misc/wifi/wpa_supplicant.conf文件是否存在,如果不存在,那么从/system/etc/wifi/wpa_supplicant.conf动态拷贝一份
android_net_wifi_connectToSupplicant
=>wifi_connect_to_supplicant
=>
ctrl_conn = wpa_ctrl_open(ifname);
monitor_conn = wpa_ctrl_open(ifname);
wpa_ctrl_attach(monitor_conn);
android_net_wifi_waitForEvent
=>wifi_wait_for_event
=>wpa_ctrl_recv(monitor_conn, buf, &nread);
=>recv(ctrl->s, reply, *reply_len, 0);//阻塞等待wpa_supplicant的netlink数据过来
=>如果接收的buf数据区,buf[0]为'<',那么说明有level级别信息,所以将'<'...'>'数据剔除,然后wifi_wait_for_event函数返回[luther.gliethttp].
java/android/android/net/wifi/WifiMonitor.java
public class WifiMonitor {
...
public void startMonitoring() {
new MonitorThread().start();//启动java线程
}
class MonitorThread extends Thread {
public MonitorThread() {
super("WifiMonitor");
}
public void run() {
for (;;) {
ensureSupplicantConnection();//=>WifiNative.connectToSupplicant调用jni函数android_net_wifi_connectToSupplicant
String eventStr = WifiNative.waitForEvent();//=>调用jni函数android_net_wifi_waitForEvent
//private static final int CONNECTED = 1;
//private static final int DISCONNECTED = 2;
//private static final String eventPrefix = "CTRL-EVENT-";
//private static final int eventPrefixLen = eventPrefix.length();
//private static final String connectedEvent = "CONNECTED";
//private static final String disconnectedEvent = "DISCONNECTED";
String eventName = eventStr.substring(eventPrefixLen);//去掉"CTRL-EVENT-"字符串
int nameEnd = eventName.indexOf(' ');//找到随后的空格位置,这在wpa_supplicant发送时
//#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "中,已经内置空格了.
if (nameEnd != -1)
eventName = eventName.substring(0, nameEnd);
int event;
if (eventName.equals(connectedEvent))//检测netlink过来的字符串action类型
event = CONNECTED;
else if (eventName.equals(disconnectedEvent))
event = DISCONNECTED;
...
int ind = eventStr.indexOf(" - ");//CTRL-EVENT-CONNECTED - Connection to ...
if (ind != -1)
eventData = eventStr.substring(ind + 3);
2:26 PM | Add a comment | Permalink | Blog it | Android
2009年11月27日 星期五
2009年11月26日 星期四
2009年11月19日 星期四
ip camera
這是屬於Justin的個人Blog, 用來紀錄一些事物或是技術文件 ...
Justin
Links
About Justin
Album
Bookmarks
Guestbook
Tags
3C產品 (13)
Computer (3)
Others (15)
USB Webcam
Vimicro Zc301P
實驗步驟:
ARM-based IPCam實驗步驟共可分為以下幾個部分:
A.Host環境設置
B.Webcam驅動程式移植
C.Webcam擷取軟體移植
D.Web Server編譯
E.Target端軟體配置與實測
A.Host環境設置
(1)在 Linux Host 上安裝 Toolchain (Cross Compiler) for NAV-270
(Host)# cd /
(Host)# tar –jxvf cross-3.4.1.tar.bz2
(Host)# export PATH=/usr/local/arm/3.4.1/bin/:$PATH
(Host)# arm-linux-gcc –v
看是否有gcc 3.4.1版本訊息出現,來得知是否已正確引入路徑。
(2)在 Linux Host 上解開2.6.9 Kernel Source Code (/usr/local/arm)
(Host)# tar –zxvf linux-2.6.9-nav-0809.tar.gz
B.Webcam驅動程式移植
(1)使用mxhaard.free.fr提供的驅動程式Linux kernel webcams Driver GSPCA / SPCA5xx來驅動Vimicro晶片之Webcam:
官方網頁: http://mxhaard.free.fr/
(2)下載usb-2.6.12LE06.patch.tar.gz
Driver 下載: http://mxhaard.free.fr/spca50x/embedded/KernelPatch/
(3)進行Kernel Patch
(Host)# cd /usr/local/arm/linux-2.6.9-nav/drivers/usb
(Host)# tar zxvf usb-2.6.12LE06.patch.tar.gz
(Host)# patch –p1 <>下的Video for linux選擇為<*>,並已內含於Kernel。接著將 USB support
---> USB Multimedia devices選項下的USB SPCA5XX Sunplus Vimicro Sonix Cameras標記成,以編譯成Modules。
(5)編譯SPCA5XX Kernel Module
(Host)# make module
(6)取得SPCA5XX Kernel Module (spca5xx.ko)
C.Webcam擷取軟體移植
使用同為mxhaard.free.fr所提供的servfox來進行Webcam影像之擷取。
官方網站: http://mxhaard.free.fr/spca50x/embedded/Servfox/
(1)下載servfox-R1_1_3.tar.gz
(2)解開servfox
(Host)# tar zxvf servfox-R1_1_3.tar.gz
(3)編譯servfox
(Host)# cd servfox-R1_1_3
(Host)# mv Makefile.arm Makefile
(Host)# vi Makefile (確認Cross-Compiler)
(Host)# make
(4)取得servfox執行檔
D.Web Server編譯
使用www.acme.com提供的thttpd進行Web Server 安裝。
(1)下載 thttpd Source Code並解壓縮:
(Host)# cd /usr/local/arm
(Host)# wget http://www.acme.com/software/thttpd/thttpd-2.25b.tar.gz
(Host)# tar zxf thttpd-2.25b.tar.gz
(2)編譯 thttpd Web-Server
(Host)# cd thttpd-2.25b
(Host)# CC=/usr/local/arm/3.4.1/bin/arm-linux-gcc ./configure host=arm-linux
(Host)# make
(3)取得thttpd執行檔
E.Target端軟體配置與實測
(1)備妥之程式與設定檔:
a.servfox (影像擷取與串流輸出程式)
b.spca5xx.ko (Webcam驅動程式)
c.thttpd (Web Server)
d.thttpd.conf (Web Server配置檔)
e.www目錄 (放置遠端監控Webcam之網頁程式)
thttpd.conf配置檔內容:
dir=/ramdisk/www
port=8080
user=nobody
nochroot
nosymlink
novhost
(2)遠端監控Webcam之網頁程式:
使用同為mxhaard.free.fr所提供的spcaview內含之http-java-applet來進行Webcam影像遠端觀看功能實
作,spcaview亦可於linux上編譯並直接與servfox進行影像串流擷取。
下載網址: http://mxhaard.free.fr/spca50x/Download/
下載spcaview-20071223.tar.gz
解開後於http-java-applet目錄中取得index.htm (原index-sample.html), control.jpg, JWebcamPlayer.jar三個檔案。
(3)將NAV270開機,並透過超級終端機由Com 1連上。
(4)使用udhcpc取得網路位址
(Target)# udhcpc
例如取得eth0之IP位址為192.168.1.105
(5)將程式檔案上傳到ARM開發版上:
(Target)# cd ramdisk
將程式與配置檔透過Zmodem協定上傳
(Target)# mkdir www
(Target)# cd www
將Web監控程式透過Zmodem協定上傳
(6)將Web監控程式設成可讀狀態
(Target)# chmod +r *
(7)將Webcam接上ARM開發版, 並載入驅動程式
(Target)# cd ..
(Target)# insmod spca5xx.ko
若成功載入驅動程式則會出現:
Using spca5xx.ko
Drivers/usb/media/spca5xx/spca_core.c: USB SPCA5XX camera found. Type Vimicro Zc301P 0x301b
Usbcore: registered new driver spca5xx
Drivers/usb/media/spca5xx/spca_core.c: spca5xx driver 00.57.06LE registered
(Target)# mknod /dev/video0 c 81 1
建立video設備節點,/dev/video0為設備名稱,c代表字元設備,81為主設備編號,1為從設備號
(8)執行servfox程式
(Target)# chmod 755 servfox
(Target)# ./servfox –h (查看可使用的參數)
(Target)# ./servfox –d /dev/video0 –s 640x480 –w 7070 &
目標裝置設為/dev/video0,擷取模式為640x480,以port 7070輸出影像串流。
(9)啟動thttp程式
(Target)# chmod 755 thttpd
(Target)# ./thttpd –C thttpd.conf
(10)於可連線的範圍內以一台具備java plugin的瀏覽器電腦開啟目標網頁:
於網址列輸入 http://192.168.1.105:8080/index.htm 即可觀看到Webcam畫面。
實驗問題記錄
第一次嘗試使用與編譯Linux Kernel 2.6.9 一樣的 Corss-compiler 3.4.1 gcc來編譯servfox可以無錯誤完成編譯,但於ARM平台上直行會出現ioctl錯誤與無法辨識Webcam的錯誤訊息- “Not a JPEG webcam sorry Abort! “,而後改用Corss-compiler 3.2.2 gcc即無此問題。
一般建立/dev/video設備節點時由於只有一個設備,通常輸入mknod /dev/video0 c 81 0,從設備號0代表僅有一個,但在此NAV270開發版上需要指定為1,判斷時可以透過/dev/v4l目錄下的節點來觀察,NAV270上推測具有預設之/dev/v4l/video0設備,而插入USB Webcab時可以觀察到會多出一個/dev/v4l/video1設備,因此從設備號需設為1。
Justin
Links
About Justin
Album
Bookmarks
Guestbook
Tags
3C產品 (13)
Computer (3)
Others (15)
USB Webcam
Vimicro Zc301P
實驗步驟:
ARM-based IPCam實驗步驟共可分為以下幾個部分:
A.Host環境設置
B.Webcam驅動程式移植
C.Webcam擷取軟體移植
D.Web Server編譯
E.Target端軟體配置與實測
A.Host環境設置
(1)在 Linux Host 上安裝 Toolchain (Cross Compiler) for NAV-270
(Host)# cd /
(Host)# tar –jxvf cross-3.4.1.tar.bz2
(Host)# export PATH=/usr/local/arm/3.4.1/bin/:$PATH
(Host)# arm-linux-gcc –v
看是否有gcc 3.4.1版本訊息出現,來得知是否已正確引入路徑。
(2)在 Linux Host 上解開2.6.9 Kernel Source Code (/usr/local/arm)
(Host)# tar –zxvf linux-2.6.9-nav-0809.tar.gz
B.Webcam驅動程式移植
(1)使用mxhaard.free.fr提供的驅動程式Linux kernel webcams Driver GSPCA / SPCA5xx來驅動Vimicro晶片之Webcam:
官方網頁: http://mxhaard.free.fr/
(2)下載usb-2.6.12LE06.patch.tar.gz
Driver 下載: http://mxhaard.free.fr/spca50x/embedded/KernelPatch/
(3)進行Kernel Patch
(Host)# cd /usr/local/arm/linux-2.6.9-nav/drivers/usb
(Host)# tar zxvf usb-2.6.12LE06.patch.tar.gz
(Host)# patch –p1 <>下的Video for linux選擇為<*>,並已內含於Kernel。接著將 USB support
---> USB Multimedia devices選項下的USB SPCA5XX Sunplus Vimicro Sonix Cameras標記成,以編譯成Modules。
(5)編譯SPCA5XX Kernel Module
(Host)# make module
(6)取得SPCA5XX Kernel Module (spca5xx.ko)
C.Webcam擷取軟體移植
使用同為mxhaard.free.fr所提供的servfox來進行Webcam影像之擷取。
官方網站: http://mxhaard.free.fr/spca50x/embedded/Servfox/
(1)下載servfox-R1_1_3.tar.gz
(2)解開servfox
(Host)# tar zxvf servfox-R1_1_3.tar.gz
(3)編譯servfox
(Host)# cd servfox-R1_1_3
(Host)# mv Makefile.arm Makefile
(Host)# vi Makefile (確認Cross-Compiler)
(Host)# make
(4)取得servfox執行檔
D.Web Server編譯
使用www.acme.com提供的thttpd進行Web Server 安裝。
(1)下載 thttpd Source Code並解壓縮:
(Host)# cd /usr/local/arm
(Host)# wget http://www.acme.com/software/thttpd/thttpd-2.25b.tar.gz
(Host)# tar zxf thttpd-2.25b.tar.gz
(2)編譯 thttpd Web-Server
(Host)# cd thttpd-2.25b
(Host)# CC=/usr/local/arm/3.4.1/bin/arm-linux-gcc ./configure host=arm-linux
(Host)# make
(3)取得thttpd執行檔
E.Target端軟體配置與實測
(1)備妥之程式與設定檔:
a.servfox (影像擷取與串流輸出程式)
b.spca5xx.ko (Webcam驅動程式)
c.thttpd (Web Server)
d.thttpd.conf (Web Server配置檔)
e.www目錄 (放置遠端監控Webcam之網頁程式)
thttpd.conf配置檔內容:
dir=/ramdisk/www
port=8080
user=nobody
nochroot
nosymlink
novhost
(2)遠端監控Webcam之網頁程式:
使用同為mxhaard.free.fr所提供的spcaview內含之http-java-applet來進行Webcam影像遠端觀看功能實
作,spcaview亦可於linux上編譯並直接與servfox進行影像串流擷取。
下載網址: http://mxhaard.free.fr/spca50x/Download/
下載spcaview-20071223.tar.gz
解開後於http-java-applet目錄中取得index.htm (原index-sample.html), control.jpg, JWebcamPlayer.jar三個檔案。
(3)將NAV270開機,並透過超級終端機由Com 1連上。
(4)使用udhcpc取得網路位址
(Target)# udhcpc
例如取得eth0之IP位址為192.168.1.105
(5)將程式檔案上傳到ARM開發版上:
(Target)# cd ramdisk
將程式與配置檔透過Zmodem協定上傳
(Target)# mkdir www
(Target)# cd www
將Web監控程式透過Zmodem協定上傳
(6)將Web監控程式設成可讀狀態
(Target)# chmod +r *
(7)將Webcam接上ARM開發版, 並載入驅動程式
(Target)# cd ..
(Target)# insmod spca5xx.ko
若成功載入驅動程式則會出現:
Using spca5xx.ko
Drivers/usb/media/spca5xx/spca_core.c: USB SPCA5XX camera found. Type Vimicro Zc301P 0x301b
Usbcore: registered new driver spca5xx
Drivers/usb/media/spca5xx/spca_core.c: spca5xx driver 00.57.06LE registered
(Target)# mknod /dev/video0 c 81 1
建立video設備節點,/dev/video0為設備名稱,c代表字元設備,81為主設備編號,1為從設備號
(8)執行servfox程式
(Target)# chmod 755 servfox
(Target)# ./servfox –h (查看可使用的參數)
(Target)# ./servfox –d /dev/video0 –s 640x480 –w 7070 &
目標裝置設為/dev/video0,擷取模式為640x480,以port 7070輸出影像串流。
(9)啟動thttp程式
(Target)# chmod 755 thttpd
(Target)# ./thttpd –C thttpd.conf
(10)於可連線的範圍內以一台具備java plugin的瀏覽器電腦開啟目標網頁:
於網址列輸入 http://192.168.1.105:8080/index.htm 即可觀看到Webcam畫面。
實驗問題記錄
第一次嘗試使用與編譯Linux Kernel 2.6.9 一樣的 Corss-compiler 3.4.1 gcc來編譯servfox可以無錯誤完成編譯,但於ARM平台上直行會出現ioctl錯誤與無法辨識Webcam的錯誤訊息- “Not a JPEG webcam sorry Abort! “,而後改用Corss-compiler 3.2.2 gcc即無此問題。
一般建立/dev/video設備節點時由於只有一個設備,通常輸入mknod /dev/video0 c 81 0,從設備號0代表僅有一個,但在此NAV270開發版上需要指定為1,判斷時可以透過/dev/v4l目錄下的節點來觀察,NAV270上推測具有預設之/dev/v4l/video0設備,而插入USB Webcab時可以觀察到會多出一個/dev/v4l/video1設備,因此從設備號需設為1。
2009年11月15日 星期日
speed up dd copy in linux
To speed up the dd command, you may try to set the block size:
dd if=system.img of=/dev/sdb2 bs=100K
it will help you to transfer in 100KB block size except in byte in last block. It will speed up the dump process a lot.
dd if=system.img of=/dev/sdb2 bs=100K
it will help you to transfer in 100KB block size except in byte in last block. It will speed up the dump process a lot.
2009年11月11日 星期三
2009年11月8日 星期日
Android查看memory usage
Android查看memory usage
在adb shell裡有幾種方法可以看memory
1. android shell裡的top
PID CPU% S #THR VSS RSS UID Name
VSS -Virtual memory 的size
RSS -就是指physical 的page
不過在android上這兩項不一定是實際的數值
第一是這裡拿到的值是process可以用的memory space
而不是實際上已經使用的memory
第二是在android上很多processes之間有share
所以phy pages是可以被share的
2. 用busybox的top
不過...............那出來的值好像都怪怪的
3.用procrank
# procrank
PID Vss Rss Pss Uss cmdline
Uss是這個process exclusive 的memory
Pss 不是很清楚
不過好像是Uss 加上 RSS/ (用這塊shared memory的process數目)
procrank的source在 mydroid/extras/procrank
主要是利用 kernel 在2.6.25後一個新的功能
在/proc/pid/裡新加一個 pagemap
http://lwn.net/Articles/230975/
4. 如果要看java heap的使用量的話
dumpsys meminfo
** MEMINFO in pid 608 [com.android.phone] **
native dalvik other total
size: 4112 3655 N/A 7767
allocated: 3829 2821 N/A 6650
free: 266 834 N/A 1100
(Pss): 2087 1785 2877 6749
(shared dirty): 1124 3952 928 6004
(priv dirty): 1968 1380 556 3904
Objects
Views: 0 ViewRoots: 0
AppContexts: 5 Activities: 0
Assets: 3 AssetManagers: 3
Local Binders: 18 Proxy Binders: 14
Death Recipients: 1
OpenSSL Sockets: 0
SQL
heap: 142 dbFiles: 0
numPagers: 2 inactivePageKB: 24
activePageKB: 0
dumpsys的source在/mydroid/frameworks/base/cmds/dumpsys
張貼者: ALLSTARS 位於 下午 12:08
在adb shell裡有幾種方法可以看memory
1. android shell裡的top
PID CPU% S #THR VSS RSS UID Name
VSS -Virtual memory 的size
RSS -就是指physical 的page
不過在android上這兩項不一定是實際的數值
第一是這裡拿到的值是process可以用的memory space
而不是實際上已經使用的memory
第二是在android上很多processes之間有share
所以phy pages是可以被share的
2. 用busybox的top
不過...............那出來的值好像都怪怪的
3.用procrank
# procrank
PID Vss Rss Pss Uss cmdline
Uss是這個process exclusive 的memory
Pss 不是很清楚
不過好像是Uss 加上 RSS/ (用這塊shared memory的process數目)
procrank的source在 mydroid/extras/procrank
主要是利用 kernel 在2.6.25後一個新的功能
在/proc/pid/裡新加一個 pagemap
http://lwn.net/Articles/230975/
4. 如果要看java heap的使用量的話
dumpsys meminfo
** MEMINFO in pid 608 [com.android.phone] **
native dalvik other total
size: 4112 3655 N/A 7767
allocated: 3829 2821 N/A 6650
free: 266 834 N/A 1100
(Pss): 2087 1785 2877 6749
(shared dirty): 1124 3952 928 6004
(priv dirty): 1968 1380 556 3904
Objects
Views: 0 ViewRoots: 0
AppContexts: 5 Activities: 0
Assets: 3 AssetManagers: 3
Local Binders: 18 Proxy Binders: 14
Death Recipients: 1
OpenSSL Sockets: 0
SQL
heap: 142 dbFiles: 0
numPagers: 2 inactivePageKB: 24
activePageKB: 0
dumpsys的source在/mydroid/frameworks/base/cmds/dumpsys
張貼者: ALLSTARS 位於 下午 12:08
2009年11月6日 星期五
訂閱:
文章 (Atom)