8/26/2011 10:19:38 PM
google API
前两天配置好了Android开发环境,并且写了Hello World,但是对Android开发还是一知半解,就像尝试一下地图的开发,因为我后面要做的工作是与地图息息相关的。
我在安装Android SDK Platform的时候顺便安装了开发示例。在Google API平台下有一个示例叫做MapsDemo,我本以为运行它就可以直接显示地图了,
结果到模拟器上面执行,只显示网格,没有半点地图的迹象。
上网搜索了一下,发现Android上面的Google Map也需要API Key。它根据应用程序的keystore的MD5签名来生成API key,
使用keytool工具可以获得keystore的获得MD5签名。Android SDK默认生成一个debug.keystore文件,放在用户主目录下的.android文件夹中,
运行keytool工具(JDK中bin目录下有 keytool工具)命令如下:
C:\Program Files\Java\jdk1.6.0_18\bin>keytool.exe -list -alias androiddebugkey -keystore C:\Users\westyi\.android\debug.keystore -storepass android -keypass android
即可得到debug.keystore的MD5签名值,然后到http://code.google.com/android/add-ons/google-apis/maps-api-signup.html 页面提交上面得到的MD5签名即可获得地图API key。
得到自己的API key之后,就要对MapsDemo进行修改,将其中需要的Map key修改为自己获得的Key。主要修改两个地方:
res/layout/mapview.xml中第30行
android:apikey="sample_api_key"
以及MapViewCompassDemo.java文件中第143行
mMapView = new MapView(this, "sample_api_key");
将sample_api_key改为自己获得的api key即可。
至此,我以为大功告成了,因为网上多数地图方面的问题都是关于API Key的,我想这个Demo也应该就是这方面的问题吧。但事实确并非如此,运行后确实不再是网格了,这次是全白的!很诡异~~~
我百思不得其解,然后就在网上拼命找与Android地图开发相关的文章,发现多数的文章中都没有理会google这个示例,而是自己动手写 Activity。
经过我对MapsDemo的代码分析,我发现代码中只是使用了MapView,而并未设置地图的缩放级别和地图中心。这可能就是显示全白界面的原因!需要对MapViewDemo.java文件进行修改,
在onCreate方法最后添加代码:
Java代码
1.MapView map = (MapView)findViewById(R.id.map);//获得MapView对象
2.map.getController().setCenter(new GeoPoint(39971036,116314659));//设置地图中心
3.map.getController().setZoom(10);//设置缩放级别
MapView map = (MapView)findViewById(R.id.map);//获得MapView对象
map.getController().setCenter(new GeoPoint(39971036,116314659));//设置地图中心
map.getController().setZoom(10);//设置缩放级别
其中R.id.map是Android SDK自动生成的,需要在res/layout/mapview.xml文件第25行加上android:id="@+id/map",为MapView 添加一个id编号,才能在代码中用findViewById获得MapView对象。
再次在模拟器中运行,亲爱的北京地图终于显示在了Android模拟器上面!
需要提交字节的API key
屏幕的分辨率
QVGA/WQVGA/HVGA/VGA/WVGA说的是手机屏幕不同的分辨率,他们之间的区别就是分辨率水平,表现出来的图像细腻度也不相同。
其中QVGA的全称是Quarter VGA,分辨率为240*320像素,一般比较老和新款低端的Windows Mobile机型采用这一分辨率;
WQVGA是QVGA的加强升级版Wide Quarter
VGA,可以看做是QVGA分辨率的加宽版本,分辨率达到了240*400像素,一般也是用在低端手机中;
HVGA的全称是Half VGA,分辨率为320*480像素,一般的中端Windows Mobile机型和较老的高端WM机型都采用这一分辨率。
VGA是最为标准的分辨率,这点从前面的介绍中就能够了解到,因为他们都是在VGA之前加了一个字母将改分辨率进行缩减。
VGA分辨率为480*640像素,一般用在中端机型和较老的高端手机中;
最后的WVGA分辨率全称是Wide VGA,分辨率达到了480*800像素或者480*854(宽屏)像素,是目前最高端的Windows
Mobile手机使用的分辨率。众所周知目前HTC HD2是当之无愧的机皇,这款手机的分辨率就达到了WVGA级别。
一般手机液晶屏幕都是TFT材质,VGA WVGA QVGA HVGE XGA只是表示屏幕分辨率只,是个代号和材质没关系。
分辨率对照表:
代号 分辨率 代号 分辨率
QVGA 320*240像素 WQVGA 400*240像素
HVGA 320*480像素 VGA 640*480像素
WVGA 800*480像素 XGA 1024*480像素
QVGA 即Quarter VGA。顾名思义即VGA的四分之一尺寸
HVGA (Half-size VGA),即VGA(640*480)的一半
WVGA 即Wide VGA
sqlite3
插入表和查询表
sqlite3 /data/data/com.android.providers.settings/databases/settings.db "INSERT INTO system VALUES(99,'http_proxy','10.10.26.252:1080')"
sqlite3 /data/data/com.android.providers.settings/databases/settings.db "SELECT * FROM system"
删除表
sqlite3 /data/data/com.android.providers.settings/databases/settings.db "DELETE FROM system WHERE _id=99"
模拟器的启动过程
在模拟器中安装APK包
adb install
读取系统属性的值qemu-props
int main(void)
{
int qemud_fd, count = 0;
/* try to connect to the qemud service */
{
int tries = MAX_TRIES;
while (1) {
qemud_fd = qemud_channel_open( "boot-properties" );
if (qemud_fd >= 0)
break;
if (--tries <= 0) {
DD("Could not connect after too many tries. Aborting");
return 1;
}
DD("waiting 1s to wait for qemud.");
sleep(1);
}
}
打开一个通道
DD("connected to '%s' qemud service.", QEMUD_SERVICE);
/* send the 'list' command to the service */
if (qemud_channel_send(qemud_fd, "list", -1) < 0) {
DD("could not send command to '%s' service", QEMUD_SERVICE);
return 1;
}
/* read each system property as a single line from the service,
* until exhaustion.
*/
for (;;)
{
#define BUFF_SIZE (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
DD("receiving..");
char* q;
char temp[BUFF_SIZE];
int len = qemud_channel_recv(qemud_fd, temp, sizeof temp - 1);
/* lone NUL-byte signals end of properties */
if (len < 0 || len > BUFF_SIZE-1 || temp[0] == '\0')
break;
temp[len] = '\0'; /* zero-terminate string */
DD("received: %.*s", len, temp);
/* separate propery name from value */
q = strchr(temp, '=');
if (q == NULL) {
DD("invalid format, ignored.");
continue;
}
*q++ = '\0';
if (property_set(temp, q) < 0) {
DD("could not set property '%s' to '%s'", temp, q);
} else {
count += 1;
}
}
/* finally, close the channel and exit */
close(qemud_fd);
DD("exiting (%d properties set).", count);
return 0;
}
也就是简单的读取了qemu的引导属性
/* we connect with the emulator through the "sensors" qemud service
*/
通过这个与模拟器进行通信???
#define SENSORS_LIST \
SENSOR_(ACCELERATION,"acceleration") \
SENSOR_(MAGNETIC_FIELD,"magnetic-field") \
SENSOR_(ORIENTATION,"orientation") \
SENSOR_(TEMPERATURE,"temperature") \
static const struct {
const char* name;
int id; } _sensorIds[MAX_NUM_SENSORS] =
{
#define SENSOR_(x,y) { y, ID_##x },
SENSORS_LIST
#undef SENSOR_
};
static const char*
_sensorIdToName( int id )
{
int nn;
for (nn = 0; nn < MAX_NUM_SENSORS; nn++)
if (id == _sensorIds[nn].id)
return _sensorIds[nn].name;
return "<UNKNOWN>";
}
从Id到名字的转换
static int
_sensorIdFromName( const char* name )
{
int nn;
if (name == NULL)
return -1;
for (nn = 0; nn < MAX_NUM_SENSORS; nn++)
if (!strcmp(name, _sensorIds[nn].name))
return _sensorIds[nn].id;
return -1;
}
通过名字找到Id
打开sensor服务
static native_handle_t*
control__open_data_source(struct sensors_control_device_t *dev)
{
SensorControl* ctl = (void*)dev;
native_handle_t* handle;
if (ctl->fd < 0) {
ctl->fd = qemud_channel_open(SENSORS_SERVICE_NAME);
}
D("%s: fd=%d", __FUNCTION__, ctl->fd);
handle = native_handle_create(1, 0);
handle->data[0] = dup(ctl->fd);
return handle;
}
control__activate
通过sensor服务来激活某个sensor
control__set_delay 设置延迟
control__wake 设置唤醒
control__close 关闭
/** SENSORS DATA DEVICE
**
** This one is used to read sensor data from the hardware.
** We implement this by simply reading the data from the
** emulator through the QEMUD channel.
**/
从hardware上读取 sensor data
/** MODULE REGISTRATION SUPPORT
**
** This is required so that hardware/libhardware/hardware.c
** will dlopen() this library appropriately.
**/
/*
* the following is the list of all supported sensors.
* this table is used to build sSensorList declared below
* according to which hardware sensors are reported as
* available from the emulator (see get_sensors_list below)
*
* note: numerical values for maxRange/resolution/power were
* taken from the reference AK8976A implementation
*/
/*
* the qemud daemon program is only used within Android as a bridge
* between the emulator program and the emulated system. it really works as
* a simple stream multiplexer that works as follows:
*
* - qemud is started by init following instructions in
* /system/etc/init.goldfish.rc (i.e. it is never started on real devices)
被init 进程启动
*
* - qemud communicates with the emulator program through a single serial
* port, whose name is passed through a kernel boot parameter
* (e.g. android.qemud=ttyS1)
*
* - qemud binds one unix local stream socket (/dev/socket/qemud, created
* by init through /system/etc/init.goldfish.rc).
*
*
* emulator <==serial==> qemud <---> /dev/socket/qemud <-+--> client1
* |
* +--> client2
串口 本地域socket进行通信
*
* - the special channel index 0 is used by the emulator and qemud only.
* other channel numbers correspond to clients. More specifically,
* connection are created like this:
*
* * the client connects to /dev/socket/qemud
*
* * the client sends the service name through the socket, as
* <service-name>
*
* * qemud creates a "Client" object internally, assigns it an
* internal unique channel number > 0, then sends a connection
* initiation request to the emulator (i.e. through channel 0):
*
* connect:<id>:<name>
*
* where <name> is the service name, and <id> is a 2-hexchar
* number corresponding to the channel number.
*
* * in case of success, the emulator responds through channel 0
* with:
*
* ok:connect:<id>
*
* after this, all messages between the client and the emulator
* are passed in pass-through mode.
*
* * if the emulator refuses the service connection, it will
* send the following through channel 0:
*
* ko:connect:<id>:reason-for-failure
*
* * If the client closes the connection, qemud sends the following
* to the emulator:
*
* disconnect:<id>
*
* The same message is the opposite direction if the emulator
* chooses to close the connection.
*
* * any command sent through channel 0 to the emulator that is
* not properly recognized will be answered by:
*
* ko:unknown command
*
*
* Internally, the daemon maintains a "Client" object for each client
* connection (i.e. accepting socket connection).
*/
fd_setnonblock 设置非阻塞
fd_accept 监听某个地址
looper_init 创建一个epoll
looper_done 释放一个epoll
looper_find 返回指定句柄上一个hook
looper_grow 扩充2倍加4个
qemu=1 console=ttyS0 android.checkjni=1 android.qemud=ttyS1 android.ndns=1
multiplexer_init
打开串口
/* initialize the serial reader/writer */
recv.user = m;
recv.post = (PostFunc) multiplexer_serial_receive;
recv.close = (CloseFunc) multiplexer_serial_close;
serial_init( m->serial, fd, m->fdhandlers, &recv );
看一下串口的读写
/* a function called when an incoming packet comes from the serial port */
static void
multiplexer_serial_receive( Multiplexer* mult, Packet* p )
{
Client* client;
T("%s: channel=%d '%.*s'", __FUNCTION__, p->channel, p->len, p->data);
if (p->channel == CHANNEL_CONTROL) {
multiplexer_handle_control(mult, p);
return;
}
client = multiplexer_find_client(mult, p->channel);
if (client != NULL) {
client_send(client, p);
return;
}
D("%s: discarding packet for unknown channel %d", __FUNCTION__, p->channel);
packet_free(&p);
}
多通道
通过通道来查找Client ?
通道控制时间什么?
ok:connect:通道号
解析这个串
static Client*
multiplexer_find_client( Multiplexer* mult, int channel )
{
Client* c = mult->clients;
for ( ; c != NULL; c = c->next ) {
if (c->channel == channel)
return c;
}
return NULL;
}
通过channel 找到Client
转发的时候
/* send data to a client */
static void
client_send( Client* c, Packet* p )
{
client_dump(c, p, __FUNCTION__);
fdhandler_enqueue(c->fdhandler, p);
}
本质上也就是也就是一个中转站而已
通过文件名来查找进程Id
struct DexSymList {
DexSymList *next;
DexSym sym;
};
符号的这样一个单链表
// This function creates the pathname to the a specific trace file. The
// string space is allocated in this routine and must be freed by the
// caller.
static char *CreateTracePath(const char *filename, const char *ext)
{
char *fname;
const char *base_start, *base_end;
int ii, len, base_len, dir_len, path_len, qtrace_len;
// Handle error cases
if (filename == NULL || *filename == 0 || strcmp(filename, "/") == 0)
return NULL;
// Ignore a trailing slash, if any
len = strlen(filename);
if (filename[len - 1] == '/')
len -= 1;
// Find the basename. We don't use basename(3) because there are
// different behaviors for GNU and Posix in the case where the
// last character is a slash.
base_start = base_end = &filename[len];
for (ii = 0; ii < len; ++ii) {
base_start -= 1;
if (*base_start == '/') {
base_start += 1;
break;
}
}
base_len = base_end - base_start;
dir_len = len - base_len;
qtrace_len = strlen("/qtrace");
// Create space for the pathname: "/dir/basename/qtrace.ext"
// The "ext" string already contains the dot, so just add a byte
// for the terminating zero.
path_len = dir_len + base_len + qtrace_len + strlen(ext) + 1;
fname = new char[path_len];
if (dir_len > 0)
strncpy(fname, filename, dir_len);
fname[dir_len] = 0;
strncat(fname, base_start, base_len);
strcat(fname, "/qtrace");
strcat(fname, ext);
return fname;
}
在c++templates这本书里,作者是如此陈述的:
1. 类模板:该类是一个模板,他代表的是:整个类家族的参数化描述。
2. 模板类:通常被用在下面几个方面:
a 作为类模板的同义词
b 从模板产生的类
c 具有一个template-id名称的类
注意这个区别
具有template-id名称的类
struct TraceReaderEmptyStruct {
};
template <class T = TraceReaderEmptyStruct>
class TraceReader : public TraceReaderBase {
public:
struct region_entry;
typedef struct symbol_entry : public T {
typedef region_entry region_type;
// Define flag values
static const uint32_t kIsPlt = 0x01;
static const uint32_t kIsVectorStart = 0x02;
static const uint32_t kIsVectorTable = (kIsPlt | kIsVectorStart);
static const uint32_t kIsInterpreter = 0x04;
static const uint32_t kIsMethod = 0x08;
uint32_t addr;
// This may hold the name of the interpreted method instead of
// the name of the native function if the native function is a
// virtual machine interpreter.
const char *name;
// The symbol for the virtual machine interpreter, or NULL
symbol_entry *vm_sym;
region_type *region;
uint32_t flags;
} symbol_type;
符号类型
在某个区域查找某个符号
MakePrivateCopy 本质上就是一个指针拷贝
// The "regions" array below is a pointer to array of pointers to
// regions. The size of the pointer array is kInitialNumRegions,
// but grows if needed. There is a separate region for each mmap
// call which includes shared libraries as well as .dex and .jar
// files. In addition, there is a region for the main executable
// for this process, as well as a few regions for the kernel.
//
// If a child process is a clone of a parent process, the
// regions array is unused. Instead, the "addr_manager" pointer is
// used to find the process that is the address space manager for
// both the parent and child processes.
//dex 文件和jar文件
template<class T>
TraceReader<T>::TraceReader()
{
static PidEvent event_no_action;
cached_pid_ = -1;
cached_func_ = NULL;
memset(&unknown_, 0, sizeof(symbol_type));
unknown_.name = "(unknown)";
next_pid_ = 0;
memset(&event_no_action, 0, sizeof(PidEvent));
event_no_action.rec_type = kPidNoAction;
next_pid_event_ = event_no_action;
for (int ii = 1; ii < kNumPids; ++ii)
processes_[ii] = NULL;
current_ = new ProcessState;
processes_[0] = current_;
next_method_.time = 0;
next_method_.addr = 0;
next_method_.flags = 0;
function_start_time_ = 0;
root_ = "";
hash_ = new HashTable<region_type*>(512);
AddPredefinedRegions(current_);
demangle_ = true;
}
traceReader的构造函数
还是从通道跟踪
qemud_channel_open
在qume 目录下查找看看
ADB的架构分析
分为2部分
adb和一个adbd
在服务器上的为一个adbd
整个adb分为4个部分
模拟器运行的几个关键img
·ramdisk.img启动系统的ramdisk镜像
·system.img初始化好的系统镜像
·userdata.img初始化好的用户数据分区镜像
10.0.2.2 访问本机服务的地址
注意模拟器的内核镜像位置
android-sdk-windows\android-sdk-windows\platforms\android-7\images
hw.lcd.density=160
sdcard.size=200M
skin.name=HVGA
skin.path=platforms\android-7\skins\HVGA
image.sysdir.1=platforms\android-7\images\
虚拟机的相关信息位置
应该是遍历目录下得所有文件就可以了
配置 和image路径
typedef struct {
#include "android/avd/hw-config-defs.h"
} AndroidHwConfig;
模拟器的配置初始化