Browsed by
月份:2017年7月

Ubuntu环境使用Gradle编译打包APK

Ubuntu环境使用Gradle编译打包APK

参考:

1,Prepare

  • gradle:
不需要单独下载,在某个项目中执行./gradlew会下载项目需要的gradle版本,最终会下载到.gradle/dist/下面,根据ZT Android APP环境规范,下载3.3-all即可。
  • JDK:单独安装Java7
apt-get install openjdk-7-jdk
  • 安装JAVA 8
下载
scp -P 10622 jdk-8u131-linux-x64.tar.gz xugangfeng@aly.zerotech.top:~/misc/
  • android-sdk:
新的sdk都是打包在android studio工具里面,但我们又不需要。我们可以先通过下载一个老的版本sdk,然后通过这个sdk里面的工具android命令下载新的sdk版本和build tools。
 tar xf android-sdk_r24.4.1-linux.tgz
完成之后,就可以使用android命令了
列出远程可以下载的sdk和tools版本
android list sdk –all
  1. 9- Android SDK Build-tools, revision 24.0.2
  2. 10- Android SDK Build-tools, revision 24.0.1
  3. ...
  4. 37- SDK Platform Android 7.0, API 24, revision 2
  5. 38- SDK Platform Android 6.0, API 23, revision 3
  6. 39- SDK Platform Android 5.1.1, API 22, revision 2
  7. 40- SDK Platform Android 5.0.1, API 21, revision 2
下载对应平台的,我下载build-tools 24.0.2和 sdk版本为22.
android update sdk -a -u -t 1,2,6,7,36,42,37
  • 更新环境变量
  1. #android sdk
  2. ANDROID_HOME=/home/andbase/workspace/misc/android-sdk-linux
  3. export ANDROID_HOME
  4. GRADLE_HOME=/home/andbase/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3/
  5. export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin:$GRADLE_HOME/bin

2,Ready Go

  • 进入项目目录,Gradle版本确认,确认gradle版本为3.3
  1. andbase@vm-10-142-132-78:ZerotechDemo$ ./gradlew -v
  2. ------------------------------------------------------------
  3. Gradle 3.3
  4. ------------------------------------------------------------
  5. Build time: 2017-01-03 15:31:04 UTC
  6. Revision: 075893a3d0798c0c1f322899b41ceca82e4e134b
  7. Groovy: 2.4.7
  8. Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
  9. JVM: 1.7.0_85 (Oracle Corporation 24.85-b03)
  10. OS: Linux 3.16.0-30-generic amd64
  • 配置好java
根据sdk版本,选择java, update-alternatives –config java/javac
  • 设置Liecense
如果不设置,否则会有这样的错误
  1. * What went wrong:
  2. A problem occurred configuring project ':app'.
  3. > You have not accepted the license agreements of the following SDK components:
  4. [Android SDK Platform-Tools].
  5. Before building your project, you need to accept the license agreements and complete the installation of the missing components using the Android Studio SDK Manager.
  6. Alternatively, to learn how to transfer the license agreements from one workstation to another, go to http://d.android.com/r/studio-ui/export-licenses.html
android list sdk –all   列出当前的platform-tools
2- Android SDK Platform-tools, revision 26
android update sdk -a -u -t 1,2
November 20, 2015
Do you accept the license ‘android-sdk-license-c81a61d9′ [y/n]: y
另外,外部依赖包constraint-layout需要使用sdkmanager命令来添加License确认
sdkmanager “extras;m2repository;com;android;support;constraint;constraint-layout-solver;1.0.2″
  • lint检查错误

在编译脚本文件app/build.gradle中的android切点添加参数

    lintOptions {
        abortOnError false
    }
同时也可以使用assembleDebug的task,忽略Lint的检查
  • 开始编译
不进行Lint检查:
gradle –daemon  assembleDebug

3,TroubleShooting

TBD
由Adb Emulator问题谈起

由Adb Emulator问题谈起

0,问题描述

进入RK3288平台,执行adb devices会有一个emulator-5554的模拟器的连接。

1,复现步骤

reboot rk3288
C:\Users\koffuxu>adb tcpip 5555
C:\Users\koffuxu>adb shell
shell@firefly:/ # adb devices
* daemon not running. starting it now on port 5038 *
* daemon started successfully *
List of devices attached
emulator-5554   device
or:
setprop service.adb.tcp.port 5555; stop adbd; start adbd;

2,port status

127.0.0.1的41114端口(adb),连接上了5555端口(adbd),认为有一个模拟器的存在。 
从而可以获得产生该问题的原因:
先启动adbd进程,监听127.0.0.1的5555端口;
再启动adb中的server,会去获得usb或者tcp链接上的adb状态,当有5555端口有响应的时候,认为有android device设备连接了,当对方的IP地址为127.0.0.1的话,就认为是emulator设备,即显示出来这个模拟器了。

3,打开调试

  1. --- a/system/core/adb/adb_trace.h
  2. +++ b/system/core/adb/adb_trace.h
  3. @@ -64,7 +64,7 @@ extern int adb_trace_mask;
  4. extern unsigned char adb_trace_output_count;
  5. void adb_trace_init(void);
  6. -# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
  7. +# define ADB_TRACING 1// ((adb_trace_mask & (1 << TRACE_TAG)) != 0)

4,修正方案

第一次尝试:注册127.0.0.1:*<->127.0.0.1:5555的连接到transport_list全局链表时的时候,把类型由local转为非local型。
结果:几番adb kill-server /start-server之后还是会有emulator出现
 第二次尝试:不把与5555的连接注册到全局链表中。
结果:emulaotr没有添加到全局链表中,但连接是存在的,netstat 还是可以看与127.0.0.1有连接,仍有风险。
第三次尝试:不与5555进行连接
 结果:没有本地的5555的连接,emulator也没有产生,其它连接也不受影响。
其它功能测试如下:
  • PC通过usb或者网线连接RK3288的adbd

    

  • RK3288的通过usb或者网线连接手机I9300的adbd
    
     socket的连接情况
    
 .105  =RK3288的IP
.55     =I9300手机的IP
.239    =PC的IP
 

5,复盘

Overview
 

 5.1,2种Service:

Host Service:不需要与device进行通讯,直接在本地查询服务,比如版本号查询服务
Local Service:需要与Device进行通信,比如adb shell服务
ADB SERVER的各种类型参考SERVICES.txt,包含Host Service和Local Service

5.2,2个监听端口:

ADB Server监听TCP:localhost:5038,是用于等待Client的命令传输,指定127.0.0.1的连接
ADBD 监听TCP:0.0.0.0:5555,是用于监听TCP/IP的adb连接请求服务,任何IP皆可以连接 ,包括127.0.0.1

5.3,2种传输媒介:

USB:只限与物理设备的传输连接
TCP/IP:包括物理设备的连接,也包括本地adb与adbd的连接(这就是产生emualtor-5554的原因)

6,adb devices命令执行流程

ADB_HOST=1表示编译进adb可执行文件,否则为adbd可执行文件
adb devices
由services.txt可知,adb devices描述如下:
  1. host:devices host:devices-l Ask to return the list of available Android devices and their
  2. state. devices-l includes the device paths in the state.
  3. After the OKAY, this is followed by a 4-byte hex len,
  4. and a string that will be dumped as-is by the client, then
  5. the connection is closed
执行adb命令,首先进入main()
main()@adb.c
=>//adb_commandline()@commandline.c
system/core/adb/adb.c::main():Handling commandline() 
=>进行一些参数判断之后,进入qury_adb()函数 
  1. if(!strcmp(argv[0], "devices")) {
  2. ...
  3. tmp = adb_query(buf);
  4. if(tmp) {
  5. printf("List of devices attached \n");
  6. printf("%s\n", tmp);
  7. return 0;
=>//adb_query()@adb_client.c打印如下
system/core/adb/adb_client.c::adb_query():adb_query: host:devices 
=>
第一步,执行host:version命令
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:version //_adb_connect()@adb_client.c
adb_connect之前,先进行adb version查询,通过Socket的方式查询SOCK_STREAM。初次会返回为负值,需要自己启动。如果已经启动就会接下来读取版本。
=>
此段打印,检查adb_connecet是否已经启动。
//调用writex(fd, tmp, 4) || writex(fd, service, len)
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a76657273696f6e host:version
//接收server的数据:adb_status(fd)
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
//连接成功,正常则返回!
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
//D(“adb_connect: service %s\n”, service);打印
system/core/adb/adb_client.c::adb_connect():adb_connect: service host:devices 
第二步,读取版本号进行比较
//因为fd>0走else流程,开始进行版本比较
//if(readx(fd, buf, 4)) goto error; 读取前面4个字节,即本次buf的长度
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303034 0004
//readx(fd, buf, n) 读取整个buf的长度,获取Version号
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303230 0020
第三步,执行host:devices命令
//版本比对成功之后,开始执行host:devices
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:devices//打印来自fd = _adb_connect(service);
//给Service写数据,包含长度的命令writex(fd, tmp, 4) || writex(fd, service, len)
//整个帧的格式[][][][]+[……]
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c//host:devices刚好为12个字节
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a64657669636573 host:devices//再写命令
////接收server的数据:adb_status(fd)
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
//命令已经写给Server了,_adb_connect正常返回
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
//adb_connect()也正常返回,打印来自    D(“adb_connect: return fd %d\n”, fd);进入adb_query
system/core/adb/adb_client.c::adb_connect():adb_connect: return fd 3
第四步,读取host:devices的返回数据
//返回到adb_query()@adb_client.c
//再读buf,第一次读buf的的前面4个字节,即长度 if(readx(fd, buf, 4))
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
//读取的buf长度为0,即没有device连接,符合打印。
30303030 0000
system/core/adb/transport.c::readx():readx: fd=3 wanted=0
system/core/adb/transport.c::readx():readx: fd=3 wanted=0 got=0
List of devices attached
有模拟器的打印,就很容易分析其中的流程
1|shell@firefly:/ $ adb devices
system/core/adb/adb.c::main():Handling commandline()
system/core/adb/adb_client.c::adb_query():adb_query: host:devices
//写host:version命令
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:version
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a76657273696f6e host:version
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
system/core/adb/adb_client.c::adb_connect():adb_connect: service host:devices
//读取版本号
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303034 0004
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303230 0020
//版本比对成功,写host:device命令
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:devices
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a64657669636573 host:devices
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
system/core/adb/adb_client.c::adb_connect():adb_connect: return fd 3
//成功返回之后,读取buf信息
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303135 0015
system/core/adb/transport.c::readx():readx: fd=3 wanted=21
system/core/adb/transport.c::readx():readx: fd=3 wanted=21 got=21//读取21个字节即emulator-5554.de[vices]
656d756c61746f722d35353534096465 emulator-5554.de
List of devices attached
//获得连接数据
emulator-5554   device

7,解决思路

设备以及状态是在server中检测和连接,在Service.c中屏蔽对127.0.0.1:5555的连接。
或者,让Server不去连接127.0.0.1:5555端口。【最终就是采用这种方法】
首先要弄懂
  • adbd是如何通过5555端口来检测是否有设备接入的。【fdevent机制:transport_registration_func
  • adb的Server端是如何去连接5555端口的。【socket机制:local_init()@transport_local.c】

       socket_loopback_client(adb_port, SOCK_STREAM),会去连接local:5555端口。

  1. addr.sin_family = AF_INET;
  2. addr.sin_port = htons(port);
  3. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  4. s = socket(AF_INET, type, 0);
  • adb的Server与adbd的5555号端口连接,这种连接是谁先发起的?

从以下注释可以看到一些端倪

client_socket_thread()@transport_local.c
  1. /* try to connect to any number of running emulator instances */
  2. /* this is only done when ADB starts up. later, each new emulator */
  3. /* will send a message to ADB to indicate that is is starting up */
  4. for ( ; count > 0; count--, port += 2 ) {
  5. (void) local_connect(port);
  6. }
看来是新的模拟器先发消息给adb的,也就是adbd发起的??!!
7.1,adb start-server在Server端的处理
adb start-server是在adb_connect的时候执行host:version命令时就执行了,并未传递到Server端。
代码段为
_adb_connect()@adb_client.c,
fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
=>根据Unix Socket通信模型,此处即创建一个lopback地址(即127.0.0.1)端口号为5038的socket client,并进行连接。
  1. addr.sin_family = AF_INET;
  2. addr.sin_port = htons(port);
  3. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  4. s = socket(AF_INET, type, 0);
  5. connect(s, (struct sockaddr *) &addr, sizeof(addr))
那么这个Socket的Server端是在哪里创建的?
main()@adb.c->adb_main()
  1. ...
  2. local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);//DEFAULT_ADB_LOCAL_TRANSPORT_PORT=5555
  3. ...
  4. char local_name[30];
  5. build_local_name(local_name, sizeof(local_name), server_port);//server_port=5038
  6. if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
  7. exit(1);
  8. }
local_init是初始化5555端口的socket,在local_init里面,会根据HOST的值,是创建一个监听5555的socket server(for adbd)还是连接5555端口的socket client?
  1. //port = 5555
  2. void local_init(int port)
  3. {
  4. ...
  5. if(HOST) {
  6. func = client_socket_thread;//在adb进程,属于soekct client
  7. } else {
  8. func = server_socket_thread;//在adbd进程,属于socket server
  9. ...
  10. adb_thread_create(&thr, func, (void *) (uintptr_t) port))
  11. ...
  12. }
接着,install_listener(local_name, “*smartsocket*”, NULL, 0)则是创建一个监听5038端口socket server。
7.2,adb devices命令在Server的处理
处理是在handle_host_request()@adb.c
  1. // return a list of all connected devices
  2. if (!strncmp(service, "devices", 7)) {
  3. char buffer[4096];
  4. int use_long = !strcmp(service+7, "-l");
  5. if (use_long || service[7] == 0) {
  6. memset(buffer, 0, sizeof(buffer));
  7. D("Getting device list \n");
  8. list_transports(buffer, sizeof(buffer), use_long);
  9. D("Wrote device list \n");
  10. send_msg_with_okay(reply_fd, buffer, strlen(buffer));
  11. return 0;
  12. }
  13. }
list_transports()方法
  1. for(t = transport_list.next; t != &transport_list; t = t->next) {
  2. len = format_transport(t, p, end - p, long_listing);
  3. if (p + len >= end) {
  4. /* discard last line if buffer is too short */
  5. break;
  6. }
主要是从transport_list这个全局链表中取出来。
这个链接是在transport_registration_func()@transport.c这个函数里添加元素的
  1. static void transport_registration_func(int _fd, unsigned ev, void *data)
  2. {
  3. ...
  4. /* put us on the master device list */
  5. t->next = &transport_list;
  6. t->prev = transport_list.prev;
  7. t->next->prev = t;
  8. t->prev->next = t;
  9. }
这个transport_registration_func()被void init_transport_registration(void)调用,注册为fdevent
  1. void init_transport_registration(void)
  2. {
  3. int s[2];
  4. if(adb_socketpair(s)){
  5. fatal_errno("cannot open transport registration socketpair");
  6. }
  7. transport_registration_send = s[0];
  8. transport_registration_recv = s[1];
  9. fdevent_install(&transport_registration_fde,
  10. transport_registration_recv,
  11. transport_registration_func,
  12. 0);
  13. fdevent_set(&transport_registration_fde, FDE_READ);
  14. }
按照道理,只要读某个socket fd,就会有回到全局链表中。
而init_transport_registration();由adb_main()调用,相当于adbd进程。
简而言之,在adbd进程,如果有其它进程读它的socket节点,将触发fdevent,会把访问它的client记录在全局列表transprot_list链表中,即devices的列表。
7.3,adb connect在Server端的处理

8,adb Server与adbd处理“客户端”的循环

8.1,在adb的Server端的处理,是在handle_host_request()@adb.c里面处理command line发过来的命令的。
由来:
在adb_main()的install_listener(local_name, “*smartsocket*”, NULL, 0)函数中,会创建一个名为*smartsocket*,监听端口为5028的socket server,同时还是注册监听事件
=>
  1. //install_listener("TCP:5038", "*smartsocket*", NULL, 0)
  2. static install_status_t install_listener(const char *local_name,
  3. const char *connect_to,
  4. atransport* transport,
  5. int no_rebind)
  6. {
  7. alistener *l;
  8. //1,填充l结构体
  9. if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
  10. if((l->local_name = strdup(local_name)) == 0) goto nomem;
  11. if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
  12. //2,local_name_to_fd会调用socet()和bin(),初始化socket server
  13. l->fd = local_name_to_fd(local_name);
  14. //3,开始install listen,用于响应客户端
  15. if(!strcmp(l->connect_to, "*smartsocket*")) {
  16. fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
  17. }
  18. fdevent_set(&l->fde, FDE_READ);
  19. //4,添加到listener_list全局链表中。
  20. l->next = &listener_list;
  21. l->prev = listener_list.prev;
  22. l->next->prev = l;
  23. l->prev->next = l;
  24. l->transport = transport;
  25. }
以上4步就完成adb server的socket server(*smartsocket*)的创建,其中第3步,安装了listen的处理,处理函数是ss_listener_event_func,继续深挖goon!
  1. static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
  2. {
  3. asocket *s;
  4. ...
  5. s = create_local_socket(fd);
  6. if(s) {
  7. connect_to_smartsocket(s);
  8. return;
  9. }
  10. }
先创建asocket类型的s,然后调用connect_to_smartsocket进行连接
=>
create_smart_socket()
=>
s->enqueue = smart_socket_enqueue;
=>
if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) 
就调到handle_host_request函数里面了。DONE!
举例:比如说host:version的处理逻辑
    // returns our value for ADB_SERVER_VERSION
    if (!strcmp(service, “version”)) {
        char version[12];
        snprintf(version, sizeof version, “%04x”, ADB_SERVER_VERSION);
        send_msg_with_okay(reply_fd, version, strlen(version));
        return 0;
    }


8.2在adbd中,是在fdevent_loop()@fdevent.c处理客户端的请求;
  1. for(;;) {
  2. D("--- ---- waiting for events\n");
  3. fdevent_process();
  4. while((fde = fdevent_plist_dequeue())) {
  5. fdevent_call_fdfunc(fde);
  6. }
  7. }
死循环处理的,fdevent_loop()是在adb_main()@adb.c即adbd初始化的时候调用到。
TOP