【Android】ADB工具原理探究

ADB简介

Android Debug Bridge (adb) 是一个Android的命令行工具。可以用来连接模拟器或实际的移动设备。比如 adb logcat, adb shell。Dalvik Debug Monitor Server(DDMS) 后台也是运行的adb来实现监控调试移动设备。

总体而言,adb有两个用途:

  • 监控连接设备 :adb会监控所有已经连接设备(包括模拟器),譬如设备所处的状态:ONLINE,OFFLINE, BOOTLOADER或RECOVERY。
  • 提供操作命令 :adb提供了很多命令(adb shelladb pull),来实现对设备的操控。这些操作命令在adb的体系里面,都称为“服务”。

ADB 实现原理

Adb的全称为 Android Debug Bridge:Android调试桥,下图为Android官方对adb的介绍:

【Android】Doze模式识别与检测

从 Android 6.0(API 级别 23)开始,Android 引入了两个省电功能:Doze模式(官方翻译为低电耗模式)和 App Standby模式(官方翻译为应用待机模式),可通过管理应用在设备未连接至电源时的行为方式为用户延长电池寿命。Doze模式通过在设备长时间处于闲置状态时推迟应用的后台 CPU 和网络 Activity 来减少电池消耗。App Standby模式可推迟用户近期未与之交互的应用的后台网络 Activity。

Doze模式

满足以下条件的设备会进入Doze低电耗模式。

  • 用户设备未插接电源
  • 处于静止状态一段时间
  • 屏幕关闭

在低电耗模式下,系统会尝试通过限制应用对网络和 CPU 密集型服务的访问来节省电量。 这还可以阻止应用访问网络并推迟其作业、同步和标准闹铃。

系统会定期退出Doze低电耗模式一会儿,好让应用完成其已推迟的 Activity。在此维护时段内,系统会运行所有待定同步、作业和闹铃并允许应用访问网络。

图 1. 低电耗模式提供了定期维护时段,可供应用使用网络并处理待定 Activity。

IPv6安全浅析

原文链接 :IPv6安全浅析 - Huawei - 2010.12 第52期

“缺乏安全性是互联网天生的弱点,这与是否采用IPv6关系不大。事实上,IPv6并没有引入新的安全问题,反而由于IPSec的引入以及发送设备采用永久性IP地址而解决了网络层溯源难题,给网络安全提供了根本的解决途径,有望实现端到端安全性。”中国电信科技委主任韦乐平这样评价IPv6安全。

IPv6协议设计的安全考虑

从协议的角度,IPv6作为IPv4的下一代,与IPv4同属于网络层的传输协议。然而,协议上最核心、最本质的差别就是地址空间的扩大,由IPv4下的32位地址空间变为128位的地址空间,这正是IPv6被选作新网络的承载协议并逐渐商用部署的根本驱动力。IPv6拥有如此巨大的地址空间,甚至可以为每一粒沙子都分配一个IP地址。而IPv4网络的地址分配是不规则的,并且很多时候是一个地址被多台主机共用。使用IPv6之后,我们能够将每个地址指定给一个责任体,就像给每个人一个身份证号,每辆车一个车牌号一样,每个地址都是唯一的;IPv6的地址分配采用逐级、层次化的结构,这就使得追踪定位、攻击溯源有了很大的改善。

另外,IPv6提出了新的地址生成方式——密码生成地址。密码生成地址与公私钥对绑定,保证地址不能被他人伪造。这如同汽车的车牌印上了指纹,别人不可能伪造这样的车牌,因为指纹造不了假。在IPv6协议设计之初,IP Sec(IPSecurity)协议族中的AH(AuthenticationHeader,报文认证头)和ESP(EncapsulationSecurity Payload,报文封装安全载荷)就内嵌到协议栈中,作为IPv6的扩展头出现在IP报文中,提供完整性、保密性和源认保护,这无疑是从协议上较大地提升安全性。

整体上看,IPv4协议的设计没有任何的安全考虑,特别是报文地址的伪造与欺骗使得无法对网络进行有效的监管和控制。因此,当出现网络攻击与安全威胁时,我们只能围绕攻击事件做好事前、事中和事后的防范、检测和过滤防御,缺乏有效的技术支撑手段,无法对攻击者形成真正的打击和管控。

而在IPv6网络的安全体系下,用户、报文和攻击可以一一对应,用户对自己的任何行为都必须负责,具有不可否认性,所以IPv6建立起严密的围绕攻击者的管控机制,实现对用户行为的安全监控。

HTTPS原理与证书生成

HTTPS

HTTPS与HTTP是什么关系呢?我们可以对比下HTTP与HTTPS的请求过程:

HTTP请求过程

HTTPS 在 TCP 和 HTTP 之间增加了 TLS(Transport Layer Security,传输层安全),提供了内容加密身份认证数据完整性三大功能。

HTTPS请求过程

WebSocket协议浅析

HTTP协议的缺点

HTTP协议的缺点

  1. 单向请求:只能是客户端发起,服务端处理并响应
  2. 请求/响应模式
  3. 无状态协议
  4. 半双工协议

半双工数据传输指数据可以在一个信号载体的两个方向上传输,但是不能同时传输。HTTP协议这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用轮询:每隔一段时候,就发出一个询问,了解服务器有没有新的信息。轮询的效率低,非常浪费资源。WebSocket就可以解决这些问题。

CPU Cache与缓存行

引言

先看下面这两个循环遍历哪个快?

1
2
3
4
5
6
7
8
9
10
11
int[][] array = new int[64 * 1024][1024];

// 横向遍历
for(int i = 0; i < 64 * 1024; i ++)
for(int j = 0; j < 1024; j ++)
array[i][j] ++;

// 纵向遍历
for(int i = 0; i < 1024; i ++)
for(int j = 0; j < 64 * 1024; j ++)
array[j][i] ++;

在CPU处理器参数为 2.3 GHz Intel Core i5 的Mac上的结果是:

横向遍历: 80ms
纵向遍历: 2139ms

横向遍历的 CPU cache 命中率高,所以它比纵向遍历约快这么多倍!

Gallery of Processor Cache Effects 用 7 个源码示例生动的介绍 cache 原理,深入浅出!但是可能因操作系统的差异、编译器是否优化,以及近些年 cache 性能的提升,有些样例在 Mac 的效果与原文相差较大。

【Java】J.U.C并发包 - AQS机制

简介

Java并发包(java.util.concurrent)中提供了很多并发工具,这其中,很多我们耳熟能详的并发工具,譬如ReentrantLock、Semaphore,CountDownLatch,CyclicBarrier,它们的实现都用到了一个共同的基类 - AbstractQueuedSynchronizer,简称AQS。AQS提供了一种原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。

设计思想

同步器背后的基本思想非常简单,可以参考AQS作者 Doug Lea 的论文:The java.util.concurrent Synchronizer Framework。同步器一般包含两种方法,一种是acquire,另一种是release。

  • acquire操作阻塞调用的线程,直到同步状态允许其继续执行。
  • release操作则是改变同步状态,使得一或多个被acquire阻塞的线程继续执行。

其中acquire操作伪代码如下:

1
2
3
4
5
while (synchronization state does not allow acquire) {
enqueue current thread if not already queued;
possibly block current thread;
}
dequeue current thread if it was queued;

release操作伪代码如下:

1
2
3
update synchronization state;
if (state may permit a blocked thread to acquire)
unblock one or more queued threads;

为了实现上述操作,需要下面三个基本组件的相互协作:

  • 同步状态的原子性管理;
  • 线程的阻塞与解除阻塞;
  • 队列的管理;

AQS框架借助于两个类:Unsafe(提供CAS操作) 和 LockSupport(提供park/unpark操作)。

1. 同步状态的原子性管理

AQS类使用单个int(32位)来保存同步状态,并暴露出getStatesetState以及compareAndSet操作来读取和更新这个状态。该整数可以表现任何状态。比如, Semaphore 用它来表现剩余的许可数,ReentrantLock 用它来表现拥有它的线程已经请求了多少次锁;FutureTask 用它来表现任务的状态(尚未开始、运行、完成和取消)。

如JDK的文档中所说,使用AQS来实现一个同步器需要覆盖实现如下几个方法,并且使用getStatesetStatecompareAndSetState这几个方法来设置或者获取状态。

  • boolean tryAcquire(int arg)

  • boolean tryRelease(int arg)

  • int tryAcquireShared(int arg)

  • boolean tryReleaseShared(int arg)

  • boolean isHeldExclusively()

以上方法不需要全部实现,根据获取的锁的种类可以选择实现不同的方法,支持独占(排他)获取锁的同步器应该实现tryAcquiretryReleaseisHeldExclusively而支持共享获取的同步器应该实现tryAcquireSharedtryReleaseSharedisHeldExclusively。下面以 CountDownLatch 举例说明基于AQS实现同步器, CountDownLatch 用同步状态持有当前计数,countDown方法调用 release从而导致计数器递减;当计数器为0时,解除所有线程的等待;await调用acquire,如果计数器为0,acquire 会立即返回,否则阻塞。

参考资料

【Android】动态链接库so的加载原理

前言

最近开发的组件时常出现了运行时加载so库失败问题,每天都会有java.lang.UnsatisfiedLinkError的错误爆出来,而且线上总是偶然复现,很疑惑。所以本文将从AOSP源码简单跟踪Android中的动态链接库so的加载原理,试图找出一丝线索。

加载入口

首先我们知道在Android(Java)中加载一个动态链接库非常简单。就是我们日常调用的 System.load(Sring filename) 或者System.loadLibrary(String libname)开始。 看过《理解JNI技术》的应该知道上述代码执行过程中会调用native层的JNI_OnLoad()方法,一般用于动态注册native方法。

# System.loadLibrary

[System.java]

1
2
3
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);
}

此处VMStack.getCallingClassLoader()拿到的是调用者的ClassLoader,一般情况下是PathClassLoader。我们进入Runtime类的loadLibrary0()方法看看。

[Runtime.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
synchronized void loadLibrary0(ClassLoader loader, String libname) {
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError("Directory separator should not appear in library name: " + libname);
}
String libraryName = libname;
// 1. 如果classloder存在,通过loader.findLibrary()查找到so路径
if (loader != null) {
String filename = loader.findLibrary(libraryName);
if (filename == null) {
// It's not necessarily true that the ClassLoader used
// System.mapLibraryName, but the default setup does, and it's
// misleading to say we didn't find "libMyLibrary.so" when we
// actually searched for "liblibMyLibrary.so.so".
throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
System.mapLibraryName(libraryName) + "\"");
}
String error = doLoad(filename, loader);
if (error != null) {
throw new UnsatisfiedLinkError(error);
}
return;
}

// 2. 如果classloder不存在,通过loader.findLibrary()查找到so路径
String filename = System.mapLibraryName(libraryName);
List<String> candidates = new ArrayList<String>();
String lastError = null;
for (String directory : getLibPaths()) { // getLibPaths()代码在最下方
String candidate = directory + filename;
candidates.add(candidate);

if (IoUtils.canOpenReadOnly(candidate)) {
String error = doLoad(candidate, loader);
if (error == null) {
return; // We successfully loaded the library. Job done.
}
lastError = error;
}
}

// 3. 都没找到,抛出 UnsatisfiedLinkError 异常
if (lastError != null) {
throw new UnsatisfiedLinkError(lastError);
}
throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2019 iTimeTraveler All Rights Reserved.

访客数 : | 访问量 :