Java 系列博客文章

Zookeeper是如何解决脑裂问题
前言

这是分布式系统中一个很实际的问题,书上说的不是很详细,整理总结一下。

1、脑裂和假死 1.1 脑裂

官方定义:当一个集群的不同部分在同一时间都认为自己是活动的时候,我们就可以将这个现象称为脑裂症状。通俗的说,就是比如当你的 cluster 里面有两个结点,它们都知道在这个 cluster 里需要选举出一个 master。那么当它们两之间的通信完全没有问题的时候,就会达成共识,选出其中一个作为 master。但是如果它们之间的通信出了问题,那么两个结点都会觉得现在没有 master,所以每个都把自己选举成 master。于是 cluster 里面就会有两个 master。举例:

UserA和UserB分别将自己的信息注册在RouterA和RouterB中。RouterA和RouterB使用数据同步(2PC),来同步信息。那么当UserA想要向UserB发送一个消息的时候,需要现在RouterA中查询出UserA到UserB的消息路由路径,然后再交付给相应的路径进行路由。

当脑裂发生的时候,相当RouterA和RouterB直接的联系丢失了,RouterA认为整个系统中只有它一个Router,RouterB也是这样认为的。那么相当于RouterA中没有UserB的信息,RouterB中没有UserA的信息了,此时UserA再发送消息给UserB的时候,RouterA会认为UserB已经离线了,然后将该信息进行离线持久化,这样整个网络的路由是不是就乱掉了。

对于Zookeeper来说有一个很重要的问题,就是到底是根据一个什么样的情况来判断一个节点死亡down掉了。 在分布式系统中这些都是有监控者来判断的,但是监控者也很难判定其他的节点的状态,唯一一个可靠的途径就是心跳,Zookeeper也是使用心跳来判断客户端是否仍然活着,但是使用心跳机制来判断节点的存活状态也带来了假死问题。

1.2 假死

ZooKeeper每个节点都尝试注册一个象征master的临时节点,其他没有注册成功的则成为slaver,并且通过watch机制监控着master所创建的临时节点,Zookeeper通过内部心跳机制来确定master的状态,一旦master出现意外Zookeeper能很快获悉并且通知其他的slaver,其他slaver在之后作出相关反应。这样就完成了一个切换。

这种模式也是比较通用的模式,基本大部分都是这样实现的,但是这里面有个很严重的问题,如果注意不到会导致短暂的时间内系统出现脑裂,因为心跳出现超时可能是master挂了,但是也可能是master,zookeeper之间网络出现了问题,也同样可能导致。这种情况就是假死,master并未死掉,但是与ZooKeeper之间的网络出现问题导致Zookeeper认为其挂掉了然后通知其他节点进行切换,这样slaver中就有一个成为了master,但是原本的master并未死掉,这时候client也获得master切换的消息,但是仍然会有一些延时,zookeeper需要通讯需要一个一个通知,这时候整个系统就很混乱可能有一部分client已经通知到了连接到新的master上去了,有的client仍然连接在老的master上如果同时有两个client需要对master的同一个数据更新并且刚好这两个client此刻分别连接在新老的master上,就会出现很严重问题。

1.3 总结

假死:由于心跳超时(网络原因导致的)认为master死了,但其实master还存活着。

脑裂:由于假死会发起新的master选举,选举出一个新的master,但旧的master网络又通了,导致出现了两个master ,有的客户端连接到老的master 有的客户端链接到新的master。

2、Zookeeper的解决方案

要解决Split-Brain的问题,一般有3种方式:

Quorums(ˈkwôrəm 法定人数) :比如3个节点的集群,Quorums = 2, 也就是说集群可以容忍1个节点失效,这时候还能选举出1个lead,集群还可用。比如4个节点的集群,它的Quorums = 3,Quorums要超过3,相当于集群的容忍度还是1,如果2个节点失效,那么整个集群还是无效的 Redundant communications:冗余通信的方式,集群中采用多种通信方式,防止一种通信方式失效导致集群中的节点无法通信。 Fencing, 共享资源的方式:比如能看到共享资源就表示在集群中,能够获得共享资源的锁的就是Leader,看不到共享资源的,就不在集群中。

ZooKeeper默认采用了Quorums这种方式,即只有集群中超过半数节点投票才能选举出Leader。这样的方式可以确保leader的唯一性,要么选出唯一的一个leader,要么选举失败。在ZooKeeper中Quorums有2个作用:

集群中最少的节点数用来选举Leader保证集群可用:通知客户端数据已经安全保存前集群中最少数量的节点数已经保存了该数据。一旦这些节点保存了该数据,客户端将被通知已经安全保存了,可以继续其他任务。而集群中剩余的节点将会最终也保存了该数据。 假设某个leader假死,其余的followers选举出了一个新的leader。这时,旧的leader复活并且仍然认为自己是leader,这个时候它向其他followers发出写请求也是会被拒绝的。因为每当新leader产生时,会生成一个epoch,这个epoch是递增的,followers如果确认了新的leader存在,知道其epoch,就会拒绝epoch小于现任leader epoch的所有请求。那有没有follower不知道新的leader存在呢,有可能,但肯定不是大多数,否则新leader无法产生。Zookeeper的写也遵循quorum机制,因此,得不到大多数支持的写是无效的,旧leader即使各种认为自己是leader,依然没有什么作用。 3、总结

总结一下就是,通过Quorums机制来防止脑裂和假死,当leader挂掉之后,可以重新选举出新的leader节点使整个集群达成一致;当出现假死现象时,通过epoch大小来拒绝旧的leader发起的请求,在前面也已经讲到过,这个时候,重新恢复通信的老的leader节点会进入恢复模式,与新的leader节点做数据同步,perfect。

原文: https://blog.csdn.net/u013374645/article/details/93140148

read more

Linux、网络相关

linux内存映射mmap原理分析

内存映射,简而言之就是将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。那么对于内核空间<---->用户空间两者之间需要大量数据传输等操作的话效率是非常高的。

二、基本函数

mmap函数是unix/linux下的系统调用,详细内容可参考《Unix Netword programming》卷二12.2节。

mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。

mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里(但是会占掉你的 virutal memory), 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后,内存中的内容并不会立即更新到文件中,而是有一段时间的延迟,你可以调用msync()来显式同步一下, 这样你所写的内容就能立即保存到文件里了.这点应该和驱动相关。 不过通过mmap来写文件这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了.如果想取消内存映射,可以调用munmap()来取消内存映射。

void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)

mmap用于把文件映射到内存空间中,简单说mmap就是把一个文件的内容在内存里面做一个映像。映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。那么对于内核空间<---->用户空间两者之间需要大量数据传输等操作的话效率是非常高的。

原理

首先,“映射”这个词,就和数学课上说的“一一映射”是一个意思,就是建立一种一一对应关系,在这里主要是只 硬盘上文件 的位置与进程 逻辑地址空间 中一块大小相同的区域之间的一一对应,如图1中过程1所示。这种对应关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在的。在内存映射的过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上被放入了内存,具体到代码,就是建立并初始化了相关的数据结构(struct address_space),这个过程有系统调用mmap()实现,所以建立内存映射的效率很高。

图1.内存映射原理

既然建立内存映射没有进行实际的数据拷贝,那么进程又怎么能最终直接通过内存操作访问到硬盘上的文件呢?那就要看内存映射之后的几个相关的过程了。

mmap()会返回一个指针ptr,它指向进程逻辑地址空间中的一个地址,这样以后,进程无需再调用read或write对文件进行读写,而只需要通过ptr就能够操作文件。但是ptr所指向的是一个逻辑地址,要操作其中的数据,必须通过MMU将逻辑地址转换成物理地址,如图1中过程2所示。这个过程与内存映射无关。

前面讲过,建立内存映射并没有实际拷贝数据,这时,MMU在地址映射表中是无法找到与ptr相对应的物理地址的,也就是MMU失败,将产生一个缺页中断,缺页中断的中断响应函数会在swap中寻找相对应的页面,如果找不到(也就是该文件从来没有被读入内存的情况),则会通过mmap()建立的映射关系,从硬盘上将文件读取到物理内存中,如图1中过程3所示。这个过程与内存映射无关。

如果在拷贝数据时,发现物理内存不够用,则会通过虚拟内存机制(swap)将暂时不用的物理页面交换到硬盘上,如图1中过程4所示。这个过程也与内存映射无关。

效率

从代码层面上看,从硬盘上将文件读入内存,都要经过文件系统进行数据拷贝,并且数据拷贝操作是由文件系统和硬件驱动实现的,理论上来说,拷贝数据的效率是一样的。但是通过内存映射的方法访问硬盘上的文件,效率要比read和write系统调用高,这是为什么呢?原因是read()是系统调用,其中进行了数据拷贝,它首先将文件内容从硬盘拷贝到内核空间的一个缓冲区,如图2中过程1,然后再将这些数据拷贝到用户空间,如图2中过程2,在这个过程中,实际上完成了 两次数据拷贝 ;而mmap()也是系统调用,如前所述,mmap()中没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,只进行了 一次数据拷贝 。因此,内存映射的效率要比read/write效率高。

图2.read系统调用原理

下面这个程序,通过read和mmap两种方法分别对硬盘上一个名为“mmap_test”的文件进行操作,文件中存有10000个整数,程序两次使用不同的方法将它们读出,加1,再写回硬盘。通过对比可以看出,read消耗的时间将近是mmap的两到三倍。

#include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/time.h> #include<fcntl.h> #include<sys/mman.h> #define MAX 10000 int main() { int i=0; int count=0, fd=0; struct timeval tv1, tv2; int *array = (int *)malloc( sizeof(int)*MAX ); /*read*/ gettimeofday( &tv1, NULL ); fd = open( "mmap_test", O_RDWR ); if( sizeof(int)*MAX != read( fd, (void *)array, sizeof(int)*MAX ) ) { printf( "Reading data failed.../n" ); return -1; } for( i=0; i<MAX; ++i ) ++array[ i ]; if( sizeof(int)*MAX != write( fd, (void *)array, sizeof(int)*MAX ) ) { printf( "Writing data failed.../n" ); return -1; } free( array ); close( fd ); gettimeofday( &tv2, NULL ); printf( "Time of read/write: %dms/n", tv2.tv_usec-tv1.tv_usec ); /*mmap*/ gettimeofday( &tv1, NULL ); fd = open( "mmap_test", O_RDWR ); array = mmap( NULL, sizeof(int)*MAX, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ); for( i=0; i<MAX; ++i ) ++array[ i ]; munmap( array, sizeof(int)*MAX ); msync( array, sizeof(int)*MAX, MS_SYNC ); free( array ); close( fd ); gettimeofday( &tv2, NULL ); printf( "Time of mmap: %dms/n", tv2.tv_usec-tv1.tv_usec ); return 0; }

输出结果:

Time of read/write: 154ms

Time of mmap: 68ms

原文:https://blog.csdn.net/mg0832058/article/details/5890688

read more
MySQL的InnoDB的幻读问题

MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”(REPEATABLE READ)。

未提交读(READ UNCOMMITTED)。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读)。 提交读(READ COMMITTED)。本事务读取到的是最新的数据(其他事务提交后的)。问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读)。 可重复读(REPEATABLE READ)。在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象(稍后解释)。 串行化(SERIALIZABLE)。读操作会隐式获取共享锁,可以保证不同事务间的互斥。

四个级别逐渐增强,每个级别解决一个问题。

脏读,最容易理解。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据。 不重复读。解决了脏读后,会遇到,同一个事务执行过程中,另外一个事务提交了新数据,因此本事务先后两次读到的数据结果会不一致。 幻读。解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。但是,如果另一个事务同时提交了新数据,本事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉。

借鉴并改造了一个搞笑的比喻:

脏读。假如,中午去食堂打饭吃,看到一个座位被同学小Q占上了,就认为这个座位被占去了,就转身去找其他的座位。不料,这个同学小Q起身走了。事实:该同学小Q只是临时坐了一小下,并未“提交”。 不重复读。假如,中午去食堂打饭吃,看到一个座位是空的,便屁颠屁颠的去打饭,回来后却发现这个座位却被同学小Q占去了。 幻读。假如,中午去食堂打饭吃,看到一个座位是空的,便屁颠屁颠的去打饭,回来后,发现这些座位都还是空的(重复读),窃喜。走到跟前刚准备坐下时,却惊现一个恐龙妹,严重影响食欲。仿佛之前看到的空座位是“幻影”一样。

一些文章写到InnoDB的可重复读避免了“幻读”(phantom read),这个说法并不准确。

做个试验:(以下所有试验要注意存储引擎和隔离级别)

mysql> show create table t_bitfly\G;
CREATE TABLE t_bitfly (
id bigint(20) NOT NULL default '0',
value varchar(32) default NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=gbk

mysql> select @@global.tx_isolation, @@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation  |
+-----------------------+-----------------+
| REPEATABLE-READ       | REPEATABLE-READ |
+-----------------------+-----------------+

试验一:

t Session A                                   Session B
|
| START TRANSACTION;            START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| empty set
|                                                             INSERT INTO t_bitfly
|                                                             VALUES (1, 'a');
|
| SELECT * FROM t_bitfly;
| empty set
|                                                             COMMIT;
|
| SELECT * FROM t_bitfly;
| empty set
|
| INSERT INTO t_bitfly VALUES (1, 'a');
| ERROR 1062 (23000):
| Duplicate entry '1' for key 1
v (shit, 刚刚明明告诉我没有这条记录的)

如此就出现了幻读,以为表里没有数据,其实数据已经存在了,傻乎乎的提交后,才发现数据冲突了。

试验二:

t Session A                                     Session B
|
| START TRANSACTION;              START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                            INSERT INTO t_bitfly
|                                                            VALUES (2, 'b');
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                            COMMIT;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|
| UPDATE t_bitfly SET value='z';
| Rows matched: 2  Changed: 2  Warnings: 0
| (怎么多出来一行)
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | z     |
| |    2 | z     |
| +------+-------+
|
v

本事务中第一次读取出一行,做了一次更新后,另一个事务里提交的数据就出现了。也可以看做是一种幻读。

那么,InnoDB指出的可以避免幻读是怎么回事呢?

http://dev.mysql.com/doc/refman/5.0/en/innodb-record-level-locks.html

By default, InnoDB operates in REPEATABLE READ transaction isolation level and with the innodb_locks_unsafe_for_binlog system variable disabled. In this case, InnoDB uses next-key locks for searches and index scans, which prevents phantom rows (see Section 13.6.8.5, “Avoiding the Phantom Problem Using Next-Key Locking”).

准备的理解是,当隔离级别是可重复读,且禁用innodb_locks_unsafe_for_binlog的情况下,在搜索和扫描index的时候使用的next-key locks可以避免幻读。

关键点在于,是InnoDB默认对一个普通的查询也会加next-key locks,还是说需要应用自己来加锁呢?如果单看这一句,可能会以为InnoDB对普通的查询也加了锁,如果是,那和序列化(SERIALIZABLE)的区别又在哪里呢?

MySQL manual里还有一段:

13.2.8.5. Avoiding the Phantom Problem Using Next-Key Locking (http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html)

To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row locking with gap locking.

You can use next-key locking to implement a uniqueness check in your application: If you read your data in share mode and do not see a duplicate for a row you are going to insert, then you can safely insert your row and know that the next-key lock set on the successor of your row during the read prevents anyone meanwhile inserting a duplicate for your row. Thus, the next-key locking enables you to “<span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px;">lock</span>” the nonexistence of something in your table.

我的理解是说,InnoDB提供了next-key locks,但需要应用程序自己去加锁。manual里提供一个例子:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

这样,InnoDB会给id大于100的行(假如child表里有一行id为102),以及100-102,102+的gap都加上锁。

可以使用show innodb status来查看是否给表加上了锁。

再看一个实验,要注意,表t_bitfly里的id为主键字段。实验三:

t Session A                                       Session B
|
| START TRANSACTION;                START TRANSACTION;
|
| SELECT * FROM t_bitfly
| WHERE id<=1
| FOR UPDATE;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                           INSERT INTO t_bitfly
|                                                           VALUES (2, 'b');
|                                                           Query OK, 1 row affected
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                           INSERT INTO t_bitfly
|                                                           VALUES (0, '0');
|                                                           (waiting for lock ...
|                                                           then timeout)
|                                                           ERROR 1205 (HY000):
|                                                           Lock wait timeout exceeded;
|                                                           try restarting transaction
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                           COMMIT;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
v

可以看到,用id<=1加的锁,只锁住了id<=1的范围,可以成功添加id为2的记录,添加id为0的记录时就会等待锁的释放。

MySQL manual里对可重复读里的锁的详细解释:

http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read

For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE),UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition. For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it. For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key (gap plus index-record) locks to block insertions by other sessions into the gaps covered by the range.

一致性读和提交读,先看实验,实验四:

t Session A                                                    Session B
|
| START TRANSACTION;                             START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
|                                                                        INSERT INTO t_bitfly
|                                                                                VALUES (2, 'b');
|                                                                        COMMIT;
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
|
| SELECT * FROM t_bitfly LOCK IN SHARE MODE;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| |  2 | b     |
| +----+-------+
|
| SELECT * FROM t_bitfly FOR UPDATE;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| |  2 | b     |
| +----+-------+
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
v

如果使用普通的读,会得到一致性的结果,如果使用了加锁的读,就会读到“最新的”“提交”读的结果。

本身,可重复读和提交读是矛盾的。在同一个事务里,如果保证了可重复读,就会看不到其他事务的提交,违背了提交读;如果保证了提交读,就会导致前后两次读到的结果不一致,违背了可重复读。

可以这么讲,InnoDB提供了这样的机制,在默认的可重复读的隔离级别里,可以使用加锁读去查询最新的数据。

http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html

If you want to see the “freshest” state of the database, you should use either the READ COMMITTED isolation level or a locking read:
SELECT * FROM t_bitfly LOCK IN SHARE MODE;

结论:MySQL InnoDB的可重复读并不保证避免幻读,需要应用使用加锁读来保证。而这个加锁度使用到的机制就是next-key locks。

==================== 结尾 ====================

作者: bitfly. 转载请注明来源或包含本信息. 谢谢
链接: http://blog.bitfly.cn/post/mysql-innodb-phantom-read/

read more
APK反编译总结
1.准备环境

win7
android-sdk_r24.0.2-windows.zip
jdk7
android studio1.5
eclipse
charles

温馨提示:后面三个工具都需要jre|jdk环境,请首先安装jdk.

2.抓包过程

通过在PC端安装charles软件,android端设置网络代理,抓取网络数据包。

2.1、PC端:在pc端创建wifi热点共享给外设->CMD命令行

netsh wlan set hostednetwork mode=allow ssid=abcd key=abcd1234

选择正在使用的网络连接,右键共享->勾选并选择刚刚创建的热点连接

netsh wlan start hostednetwork

charles:proxy setting 设置代理端口,若需https抓包请设置ssl选项,并且客户端安装charles证书

2.2、客户端:WLAN设置刚创建的“abcd”共享,并指定代理IP和端口号(自己ipconfig查看即可)

3.准备反编译工具

主要针对jvm的class文件和android虚拟机字节码smali,所需软件如下:

apktool_2.0.0rc4.zip ---- 可以得到apk里的资源和smali文件 dex2jar-2.0.zip ---- 获得class文件 jd-gui.exe ---- 反解class文件 signapk.rar ---- 修改smali或者资源文件,重新打包签名,***DEBUG*** 4.开始吧

这里以反编译土豆 app为例:

得到res和smali

java -jar apktool.jar d -d ..\..\youku\tudou\tudoushipin_61.apk -o ..\..\youku\tudou\tudoushipin_61

得到class

dex2jar.bat tudoushipin_61.apk

对上面的class使用jd-gui反编译,并导入eclipse

5.上演调试 && android studio

将smali文件导入到android studio

5.1、找到刚才apktool反解的目录找到AndroidManifest.xml,LAUNCHER对应的Activity标签上加入可被debug的配置android:debuggable="true",并保存。

5.2、假设我们现在把断点加载app的启动入口:
找到APK的入口Activity类(搜索关键字LAUNCHER你懂得),也就是:com.tudou.ui.activity.WelcomeActivity。

到了关键性的一步,找到这个Activity对应的smali文件;
定位到入口方法:onCreate;
在下面加入DEBUG代码,app启动时加入断点会停在这个位置;
说明一下:这段代码是smali的语法更多了解可以自行Google,OK。

a=0;// invoke-static {}, Landroid/os/Debug;->waitForDebugger()V

说明:根据你的需要可以把断点加到任意位置,前提是你要知道它在对应的smali文件的哪一行:方法是拿反编译后的Java文件和smali对应着去看,然后再找;后面的DEBUG也是这个思路(剧透)。

5.3、对修改后的apk重新打包

i.重新打包:

java -jar apktool.jar b -d ..\..\youku\tudou\tudoushipin_61 -o debug-tudou.apk

ii.重新签名:

java -jar signapk\signapk.jar signapk\testkey.x509.pem signapk\testkey.pk8 debug-tudou.apk debug-tudou.sign.apk

iii.一切可能都不是那么顺利):(

5.4、开启android studio-->基于知名的IntelliJ IDEA开发

1.导入之前反编译得到的smali文件到android studio,并在‘前面加debug代码’的地方加入断点。
2.找一部android手机(模拟器就算了,又慢又总是不兼容),安装刚才的签名后的apk,通过USB数据线接入PC。

5.5、有一些必要的说明

1.默认安装完android studio,例如:C:\dev\android\sdk
2.对于android Dalvik虚拟机的调试监控,DDMS已经被废弃了,新的是tools下的monitor工具,将其启动
3.在monitor中会看到devices中会出现小手机图标,端口号一般是8600

6.开始远程调试

1.android studio中菜单栏->RUN->Edit Configuration -> Remote(这根在eclipse中差不多)
指定host:localhost,端口:8600,module:smali所在的位置
启动app-->运行debug即可 -> 顺利的话光标会定位到你刚才的断点处。

2.观察Android Monitor窗口
观察Debugger tag,可以查看对象和变量的值

@hell 分享

read more

交流讨论专区,各种水~

团队文化价值观

认知、理解、判断或抉择,也就是人认定事物、辩定是非的一种思维或取向。

价值观是什么?我个人理解是一个人对事物的认知、理解,然后辨别是非的一种思维取向。而对于一个团队来说,团队所有成员共同的价值取向,以及在工作过程中遵循的基本信念和奉行的目标则是一个团队的文化价值观念。它是团队成员各项行为的准则,是凝聚团队的力量,也是团队向前的动力所在。比如 “主动敢担当、坚持再改变”,又如 “坦诚、协作、担当、进取”。

1、团队文化价值观的提法?

我认为和公司的价值观保持一致即可,坦诚、协作、担当、进取。只是不同的业务部门会针对企业核心价值观有更恰当的侧重点和发散方向。

2、如何落地?我对技术人员的几点看法。

坦诚:
从个人来讲,要善于发现自己的问题,并及时告知,然后解决;
从团队来讲,要与产品、运营同学沟通,尽可能保证信息对称,不能随意评估开发工期,故意拖延。

协作:
个人在技术开发遇到困难时,如果花费很多时间还未解决,应该及时求助其他同事帮助解决;被其他同事寻求帮助时,应该积极友善的去帮助别人;
在团队中,要积极参加产品头脑风暴,贡献idea,和产品、运营同学精诚协作,换位思考,不能随便砍需求,正确评估需求合理性;

担当:
自己遇到棘手、繁琐的任务时,应该积极主动的承担下来;
对自己的代码负责,不让其他同事承担自己的技术债。

进取:
不断学习新技术、在个人成长方面制定长期目标;
在团队、公司进行技术学习分享,提高自己的技术和团队的技术实力。最终达到个人团队共同成长,相互促进。

3、团队文化价值观能否在团队中产生作用?

我认为答案是不证自明的。

举个最接地气的例子,关于考勤,每天让我坚持起床上班不迟到的原因是什么?当然是价值观,肯定不是因为被帅醒。

因为我认为准时上班是一个合格员工应该也必须遵循的基本准则,这就是价值观的能动作用。

团队每个人如果都能从更深层次来解读和运用我们的价值观,那么我想,至少不会有迟到这样的问题。

当然,考勤只是我们的底线。作为一个成熟的企业员工,我们应该把团队价值观内化为我们的行为准则并身体力行。

有了团队价值观,即使遇到再难的项目,它都能够激发我们的动力并指引我们去完成,例如,为了一个项目能按时完成,我们可以加班加点;为了能想出更好的解决问题的办法,我们可以不眠不休的进行亢奋、激烈的讨论,为一个完美的方案,极尽所能地发散思维。

同时,团队的文化价值观不仅仅作为指引每一个人前进的灯塔,也是限制我们行为的轨道,在难以抉择的时候,让我们知道应该如何选择,知道什么能干什么不能干。

所有以上都潜移默化的在我们的工作中,并产生持久而稳定的影响,最终促进个人,团队的协同发展。

最后,我们应该在心里时刻提醒自己 “丰碑无语,行胜于言” 。

read more
Solidity IDE Remix中文版
E

Remix是以太坊官方开源的Solidity在线集成开发环境,可以使用Solidity语言在网页内完成以太坊智能合约的在线开发、在线编译、在线测试、在线部署、在线调试与在线交互,非常适合Solidity智能合约的学习与原型快速开发。

Solidity IDE中文版Remix由汇智网提供,国内CDN加速,访问地址:http://remix.hubwiz.com

如果要快速掌握以太坊智能合约与DApp开发,推荐汇智网的以太坊开发系列教程

Solidity IDE Remix为左中右三栏布局,左面板为Remix文件管理器,中间为文件编辑器,
右侧为开发工具面板:

1、Solidity IDE Remix文件管理器

Remix左面板中的文件管理器,用来列出在浏览器本地存储中保存的文件,分为browser和config两个目录,
当你第一次访问Remix的时候,在browser目录下有两个预置的代码:ballot.sol合约以及对应的单元测试
文件ballot_test.sol,点击文件名就可以在中间的文件编辑器中查看并编辑代码:

Remix文件管理器顶部的工具栏提供创建新文件、上传本地文件、发布gist等快捷功能,你可以将鼠标移到
相应的图标处停顿,然后查看功能的浮动提示信息。

为了后续功能的学习,你可以点击左上角的+创建一个新的solidity合约文件,在弹出的对话框中,将
文件命名为hello.sol:

点击[ok]按钮后,你就可以看到在左面板的文件管理其中browser目录下出现了hello.sol文件名,
同时在中间区域的文件编辑器中自动打开了这个新创建的文件等待编辑,现在它还是空的,我们将在下面
编写简单的Solidity代码。

2、Solidity IDE Remix编辑器及终端

Solidity IDE Remix中间区域为上下布局,分别提供文件编辑功能和终端访问功能。

2.1 Remix文件编辑器

Solidity IDE Remix中间区域上方的文件编辑器支持同时打开多个文件,当前激活的文件,其文件名以粗体显示:

Remix文件编辑器顶部左右两侧的箭头,分别用来切换左右面板的显示与隐藏;左上角的+和-,
分别用来放大或缩小编辑器里的文本字体大小。

现在我们激活hello.sol文件,然后输入简单的合约代码:

pragma solidity ^0.5.1; contract Hello{ function echo(string memory text) public pure returns(string memory) { return text; } }

基本上这是最简单的以太坊合约了,它只有一个echo()方法,作用就是把输入的字符串
再原样返回。

2.2 Remix终端

Solidity IDE Remix中间区域下方为终端,可以输入JavaScript命令与Remix IDE或区块链节点交互:

Remix终端内置了web3.js 1.0.0、ether.js、swarmgy以及当前载入的Solidity编译器,因此你可以
在终端内使用熟悉的web3 API与当前连接的区块链节点交互。

Remix终端同时也内置了remix对象,可以利用它来脚本化地操作Solidity Remix IDE,例如载入指定
url的gist,或者执行当前显示的代码。将终端显示向上滚动到开始位置,就可以看到remix对象的
常用方法描述。

Remix终端的另一个作用是显示合约执行或静态分析的运行结果。例如,当你部署一个合约后或执行
一个合约方法后,就会在终端看到它的执行信息:

点击信息行右侧的下拉图标,就可以查看该信息的详情;点击[debug]按钮,就会打开右侧面板中的
调试页对合约进行单步或断点调试。

Remix终端顶部的工具栏提供了切换终端显示状态、清理终端输出等功能,显示待定交易的量,
选择监听交易的范围,也可以搜索历史交易。

3、Solidity IDE Remix功能面板

Solidity IDE Remix的右侧为功能面板,以选项页的方式提供编译、运行、静态分析、测试、
调试、设置和技术支持功能。

3.1 编译选项页

在编译选项页,你可以点击下拉框切换当前要使用的Solidity编译器版本:

然后点击[开始编译]按钮,就会编译Remix文件编辑器中当前选中的代码文件,比如我们的
hello.sol文件。编译完成后,如果没有编译错误,就可以看到合约名字Hello出现在编译
选项页的合约下拉框中:

可以点击[swarm]按钮将编译好的合约上传到Swarm网络,或者点击[详情]按钮查看编译
结果详情,也可以点击[ABI]或[字节码]按钮,分别将合约的ABI与字节码拷贝到系统剪切板
以便在其他程序中使用。

3.2 运行选项页

在运行选项页,可以部署编译好的合约,也可以执行已部署合约的方法:

节点环境选项提供三种选择:JS虚拟机、注入Web3对象或使用web3提供器。

JS虚拟机是一个JS版本的以太坊虚拟机实现,它运行在你的浏览器内,因此你不需要考虑
节点配置或者担心损失以太币,最适合学习和快速原型验证。 如果你的浏览器安装了Metamask插件,或者使用Mist之类的以太坊兼容浏览器,那么也
可以选择第二个环境:使用注入的Web3对象。 如果你有自己的节点,那么可以选择第三个选项使用web3提供器来让Remix连接
到你的节点上,不过如果要连接的节点是接入以太坊主网的,要注意每一次交易都是
有成本的!

如果之前有编译好的合约,在运行选项页就可以看到这个合约的名字,例如我们的Hello。
点击[部署]按钮就可以将这个合约部署到我们选定的节点环境了:

现在可以看到,已部署的合约区域,已经出现我们的合约了。点击这个合约实例,
可以看到我们为Hello合约定义的echo方法自动显示出来了:

在方法名后面的输入框里输入方法参数,例如"helloooooooooooooo",然后点击方法名,
就可以执行合约的方法了:

你看到,返回值的确和我们输入的参数是一样的,我们实现了预定目标!

3.3 其他选项页

Solidity Remix集成开发环境还有很多功能值得研究,这个工作留给你自己了。我们只对其他
的选项页做简单介绍:

分析选项页提供对Solidity合约代码的静态分析选项。 测试选项页提供单元测试能力,你可以生成一个测试文件,或者执行一组测试。 调试器选项页可以单步跟踪合约的执行、查看合约状态或局部变量等。 设置选项提供Solidity Remix IDE本身的一些参数调整能力,例如设置编辑器文本自动折行、
启用插件、设置gist访问令牌,或者切换Remix IDE的皮肤主题 —— 目前只有三个:浅色、深色和净色。

原文:Solidity IDE Remix中文版 - 汇智网

read more
2019-02-26 听力打卡《参观自由女神像》

链接:https://dict.eudic.net/webting/desktopplay?id=0aa666b0-148d-11e9-8449-000c29ffef9b&token=QYN+eyJ0b2tlbiI6IiIsInVzZXJpZCI6IiIsInVybHNpZ24iOiJuOEc3d05JUmIxYlhsK3dFdzRQSXVVNnZzaVk9IiwidCI6IkFCSU1UVTNNRGt4TmpFM09BPT0ifQ%3D%3D

Ladies and Gentlemen, this is the Statue of Liberty , it's one of the American symbols.
It's really spectacular.
The statue has for a century acted as a figurehead for the American Dream.
I think we can climb to the top, Can't we ?
Of course you can.

词串:

spectacular
英 /spek'tækjʊlə/ 美 /spɛk'tækjəlɚ/ adj. 壮观的,惊人的;公开展示的 has for a century / have for a century
已经有一个世纪了 acted as a figurehead for American Dream.
被认为是美国梦的象征。 climb to
爬到

复习:
2019-02-28

read more