Noobzhang

  • 首页

  • 标签

  • 分类

  • 归档

Java abstract

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 Java

抽象可以修饰抽象类和抽象方法。
抽象类一般作为基类,提炼了派生类们相同的接口特征(但基类中不实现而在派生类中实现)和属性。
抽象接口,所在类一般也为基类,只有该方法可暂时不进行实现,而在派生类中实现。

  1. 抽象类不能被实例化。
  2. 抽象类中不一定要包含abstrace方法。即:抽象中可以没有abstract方法。
  3. 一旦类中包含了abstract方法,那类该类必须声明为abstract类。

示例讲解

/Animal.java ——————————————/
package me.jingg.java.AbstractTest;

public abstract class Animal { //abstract类不能实例化;供外部 包内类继承
protected String name;
protected int age;

private void eatBase() {}
public void eat() {}             //派生类可重写
public void run() {}             //派生类可重写
public abstract void showInfo(); //+abstract: 不确定具体函数定义的可以只声明, 后面再派生类中定义

}

/Cat.java ———————————-/
package me.jingg.java.AbstractTest;

public class Cat {
final private eat_fish_num;

public static main(int argc, char **argv) {

}

public void run() { //重写
    System.out.println("cat run")
}
public void showInfo() { //定义
    System.out.println("I'am a cat")
}

}

C++ 基本语法

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

基本语法:new、

new关键字

new创建基本类型变量

void ptr = new char; new short; new int; new float; //delete ptr
void
ptr = new int(5); //初始值5
void *ptr = new int[100]; //100个元素的int数组; delete []ptr
void **ptr = new int[5][6]; //delete [][]ptr

new创建类

Test test; Test test = Test(); Test pTest = new Test(1)
Test test(1); Test test = Test(1); Test
pTest = new Test();

reinterpret_cast <new_type>

C++的构造函数和析构函数

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

构造函数调用顺序:Base::Constructor->Sub::Constructor
析构函数调用顺序:Sub::Destructor->Base::Destructor
一个类中只能有一个默认构造函数(提供了无参数构造函数或者默认参数构造函数,都属于默认构造函数,只能选其一)

基本

#include
using namespace std;

class Base {
public:
Base() { cout << “Base:Base()” << endl;}
virtual ~Base() { cout << “Base:~Base()” << endl;}

virtual void showInfo() { cout << "Base::showInfo()" << endl;}

};

class Sub : public Base {
private:
int data;
public:
//Sub() {data = 0;} //默认构造函数(只选其一)
Sub(int data=4) {this->data = data; cout << “Sub:~Sub(int data=4)” << endl;} //默认构造函数(只选其一)
void v3() { cout << “Call Sub::v3, data = “ << data << endl; }

~Sub() {cout << "Sub:~Sub()" << endl;}

virtual void showInfo() { cout << "Sub::showInfo()" << endl;}

};

int main(int argc, char** argv) {

Sub* s = new Sub();
s->showInfo();
delete s;

Base* s2 = new Sub();
s2->showInfo();
delete s2; 
/*如果基类析构函数不加virtual;这样的删除只能属于静态编译调用的是基类析构,
所以只删除基类对象,而我们想要的是调用Sub类析构(Sub类析构会自动调用Base类析构)
*/
return 0;

}

私有构造/析构函数

class singleton {
private:
singleton() {}
~singleton() {}

public:
static singleton* GetSingleton(){
return new singleton();
}
};

Java反射:getClass x.class Class.forName

发表于 2016-05-27 | 更新于 2019-03-08 | 分类于 Android

1. class装载验证流程

Class的装载过程(也就是从字节码文件到生成类的实例这个过程)分为三个阶段
loading(装载),linking(连接)和initializing(实例化)

Java_reflect.png

1.1 加载

装载类的第一个阶段
通过类的全限定名(eg: com.company.Employee)取得类的二进制流
转为方法区数据结构
在Java堆中生成对应的java.lang.Class对象

1.2 链接 -> 验证

目的:保证Class流的格式是正确的

文件格式的验证

是否以0xCAFEBABE开头
版本号是否合理
元数据验证

是否有父类
继承了final类?
非抽象类实现了所有的抽象方法
字节码验证 (很复杂)

运行检查
栈数据类型和操作码数据参数吻合
跳转指令指定到合理的位置
符号引用验证

常量池中描述类是否存在
访问的方法或字段是否存在且有足够的权限

1.3 链接 -> 准备

分配内存,并为类设置初始值 (方法区中,关于方法区请查看Java内存区域)

public static int v=1;
在准备阶段中,v会被设置为0
在初始化的中才会被设置为1
对于static final类型(常量),在准备阶段就会被赋上正确的值
public static final int v=1;

###1.4 链接 -> 解析

1.5 初始化

执行类构造器

static变量 赋值语句
static{}语句

2. 什么是类装载器ClassLoader

ClassLoader是一个抽象类
ClassLoader的实例将读入Java字节码将类装载到JVM中
ClassLoader可以定制,满足不同的字节码流获取方式(譬如从网络中加载,从文件中加载)
ClassLoader负责类装载过程中的加载阶段

3. Android中java反射使用

Java的每个类必需被JVM加载到虚拟机中,然后就有一个运行时类对象,该Class对象中保存了创建对象所需的所有信息。

方法1.1:用于类提前已被加载,通过全限定名来获得类,法1——xxx.class

可以用.class返回此 Object 的运行时类Class对象,如: //.class一般用于获得类型,JVM中加载已经加载过的类
Class<?> clazz = com.android.systemui.statusbar.SystemBars.class
clazz.newInstance(); //实例化

方法1.2:用于类提前已被加载,通过实例对象来获取类,法2——getClass

也可以用getClass()获得。 //
获得此对象后可以利用此Class对象的一些反射特性进行操作,
例如://使用前类已加载
Class<?> clazz = this.getClass(); //用缺省构造函数创建一个该类的Class<?>对象
clazz.newInstance(); //用缺省构造函数创建一个该类的对象
clazz.getInterfaces(); //获得此类实现的接口信息
clazz.getMethods(); //获得此类实现的所有公有方法

方法2: 加载类到JVM中(使用全限定名),并初始化 ——Class.forName

Class<?> clazz = Class.forName(“类名,如’java.lang.Thread’ “); //动态加载类,并返回具有指定名的类的 Class 对象
在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作

Class.forName有两个调用方法

1. 常用的 Class.forName("xx.xx")      //查找并加载类,最后执行了类static代码
2. 多参数 Class.forName("xx.xx",true,CALLClass.class.getClassLoader())      //可指定是否初始化static语句,及指定类加载器

方法3:加载类到JVM(使用全限定名),但不初始化——loadClass

Class<?> clazz = loader.loadClass(“xx.xx”); 或者mContext.getClassLoader().loadClass(clsName); 都只是加载了类,但是没有执行类静态代码
使用loadClass只有执行clazz.NewInstance()才能够初始化类

参考

http://blog.csdn.net/sunyujia/article/details/2501709

Java为什么支持反射机制?

发表于 2016-05-27 | 更新于 2019-03-08 | 分类于 Java

Java为什么能够支持Reflection? 答案是Java运行时仍然拥有类型信息,它包含了这个类一切:它有哪些字段、哪些方法,各是何种保护级别等等,还有这个类依赖于哪些类。在Java中,类信息以对象的形式存放,这些对象是一种元对象,它们的类型就是Class。拥有了这些信息,无论是动态创建对象还是调用某些方法都是轻而易举的。在C++中,通过RTTI(运行时类型识别),我们也可以知道类的一些信息,但为什么C++中却没有 Reflection,原因是类型信息不完整。RTTI这个名字本身就告诉我们,C++的类型信息是用来进行类型识别的,因此,它也不需要其它额外的信息。并不是C++无法做到这一点,而是C++不希望给用户增加额外的负担。有所得,必然有所失,因此,C++放弃了元对象。关于这一点,C++之父 Bjarne Stroustrup在他的《C++语言的设计与演化》的14.2.8节中进行了深入的讨论。

元对象是Java Reflection的物质基础,那它的精神基础又是什么呢?Java为什么要支持Reflection?

经过上面的讨论,我们把这个问题再进一步,为什么Java要提供元对象?讨论这个问题,我们还要拉回到十年前,那时Java刚刚来到正式登上历史的舞台。Java实际上诞生在这之前的数年,那时候还叫Oak,环境所限使得这一划时代的杰作甫一出炉便被束之高阁。当Netscape掀起了为网络大戏的序幕,Java得以凤凰涅?,这其中很重要的一个原因就是Java是以网络为中心的。

仔细观察,我们会发现,Java的整个基础架构的设计都是为网络服务。首当其冲的便是Java中最著名的跨平台。其实,在Java之前的年代,人们也需要考虑平台之间的可移植性,但这种移植大多数集中在源码一级,这也就是C语言可以流行的原因之一,在单机环境下,平台的差异并不那么明显。网络的出现使平台之间差异凸现出来,因为网络可能会连接各种各样的计算机和设备。没错,还有设备,你也许知道Java最初的开发是和嵌入式设备相关的。一旦应用可以跨平台,程序开发和后期管理维护工作将得到极大的简化,可移植性也从源码级晋升到二进制级(Java字节码)。所以,跨平台实际上也是为了网络打基础。Java中另一个重要的买点??安全性与网络之间的关系更为密切,谁都可以想出几条理由,把二者关联起来。

再来具体看看Java的基础架构如何对网络进行支持的。还记得Java最初是怎么吸引人的吗?没错,Applet。熟悉原理的朋友都知道,Applet的运行是把远程的类文件下载到本地来执行的。相对于本地硬盘,网络给我们的感觉就是一个字????慢。如果Java采用传统可执行文件组织方式,即一个完整的可执行文件,把整个 Applet下载下来的运行,只怕等到花儿也谢了。Java采用的手法是把文件拆开,以类为单位进行组织,这就是我们今天见到的class文件。这样,执行的过程就变成第一个类下载之后就可以运行,大大节省了最初的等待时间。好的设计会把程序分成若干的模块,所以,绝大多数程序不可能写在一个类中。因此,类文件中必须包含它所用到类。对于引导部分,我们可以让它以特定的方式开始执行,比如把我们耳熟能详的main方法放在特定的字节,但对于没有定法的任意方法,是没有办法规定的,而一个类调用另一个类的方法就是这样随意,因此类文件中必须包含这个类方法的信息,进一步字段信息也会加进来,这样几乎一个完整类的信息就出来了,而这些信息对应的恰好是元对象。所以,元对象出现在Java基础架构中。有了元对象,Reflection也成了一件顺其自然的事情。有了Reflection,Java也就拥有了动态扩展的能力,这样就可以极大的提高程序的灵活性。

关于Java基础结构对网络的支持还可以再说几句。class文件经过了精心的设计,本身相当紧凑,其目的就是为了方便在网络上传输,而JAR文件的出现,其目的也是为了方便网络传输,因为如果每次只传输一个类,大量的时间都被浪费在建立网络连接的过程中,JAR文件使得一次传输多个类成为可能,而且我们还知道JAR文件中的数据是经过压缩的,这样可以进一步减少下载时间。Java基础架构对网络的支持,《深入Java虚拟机》(第二版)的4.3节进行了很好阐述,有兴趣不妨看一下。对Reflection思考让我有机会对Java本身的设计进行深入的思考。一个好的软件设计需要一个核心理念作为支撑,所有的一切都是围绕核心进行的,而对于Java,这个核心就是网络。一次有趣的思考体验!

Java中newInstance()和new()

发表于 2016-05-27 | 更新于 2019-03-08 | 分类于 Java

在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法。通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态加载类。在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作。因此,单单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象。

这里有必要提一下就是Class下的newInstance()和new有什么区别?,首先,newInstance( )是一个方法,而new是一个关键字,其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用new关键字生成对象没有这个限制。
好,到此为止,我们总结如下:
Class.forName(“”)返回的是类 class
Class.forName(“”).newInstance()返回的是object
有数据库开发经验朋友会发现,为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢?即:有的jdbc连接数据库的写法里是Class.forName(“xxx.xx.xx”);而有一些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?
刚才提到,Class.forName(“”);的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的Driver类的代码都必须类似如下:

public class MyJDBCDriver implements Driver {  
    static {  
        DriverManager.registerDriver(new MyJDBCDriver());  
    }  
}  

既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。
Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如:
class c = Class.forName(“Example”);
factory = (ExampleInterface)c.newInstance();
其中ExampleInterface是Example的接口,可以写成如下形式:
String className = “Example”;
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
进一步可以写成如下形式:
String className = readfromXMlConfig;//从xml 配置文件中获得字符串
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。

但是使用newInstance()方法的时候,就必须保证:1、这个 类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

最后用最简单的描述来区分new关键字和newInstance()方法的区别:
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。

Android Log

发表于 2016-05-26 | 更新于 2019-03-08 | 分类于 Android

Android 各层中日志打印功能的应用

1. HAL层

头文件:

#include <utils/Log.h>
Android.mk中:

LOCAL_SHARED_LIBRARIES := liblog libcutils

对应的级别 打印方法
VERBOSE LOGV()
DEBUG LOGD()
INFO LOGI()
WARN LOGW()
ERROR LOGE()

方法:
LOGD(“%d, %s”, int, char* )

2. JNI层

头文件:

#include <utils/Log.h>

对应的级别 打印方法
VERBOSE LOGV()
DEBUG LOGD()
INFO LOGI()
WARN LOGW()
ERROR LOGE()

方法:
LOGD(“%d, %s”, int, char* )

3. FRAMEWORK层

import android.util.Slog;

对应的级别 打印方法
VERBOSE Slog.v()
DEBUG Slog.d()
INFO Slog.i()
WARN Slog.w()
ERROR Slog.e()

方法:
Slog.d(TAG, “something to say.”);

4. Java层

import android.util.Log;

对应的级别 打印方法
VERBOSE Log.v()
DEBUG Log.d()
INFO Log.i()
WARN Log.w()
ERROR Log.e()

方法:
Log.d(TAG, “something to say.”);


一、LOG等级:Verbose,Debug,Info,Warn,Error, Assert,Suppress】

Verbose最低级别,什么信息都输出;A是最高级别的日志,即assert;S表示Suppress,即停止该日志的输出。

二、选用标准:

Verbose:开发调试过程中一些详细信息,Verbose等级的Log,请不要在user版本中出现

Java示例
import android.os.Build;
import android.util.Log
final public Boolean isEng =Build.TYPE.equals(“eng”);
if (isEng)
Log.v(“LOG_TAG”,“LOG_MESSAGE”);

C/C++示例

#include<cutils/log.h> ———–C/C++示例———-
char value[PROPERTY_VALUE_MAX]; int isEng=0;
property_get(“ro.build.type”,value, “user”);
isEng=strcmp(value, “eng”);
if (isEng)
ALOGV();

Debug: 用于调试的信息,编译进产品,但可以在运行时关闭,Debug等级的log,默认不开启,通过终端命令开启;

Java示例
import android.util.Log ———————————
final String TAG=”MyActivity”;
final public Boolean LOG_DEBUG = Log.isLoggable(TAG, Log.DEBUG);
if (LOG_DEBUG)
Log.d(“LOG_TAG”,“LOG_MESSAGE”);

运行时开启log: 在终端输入:setprop log.tag.MyActivity DEBUG
运行时关闭log: 在终端输入:setprop log.tag.MyActivity INFO

C/C++示例

#include<cutils/log.h> —————–

#define LOG_CTL "debug.MyActivity.enablelog"
charvalue[PROPERTY_VALUE_MAX]; 
int isDebug=0;
property_get(LOG_CTL, value, "0");
isDebug = strcmp(value,"1");
if (isDebug)
    ALOGD();

运行时开启log: 在终端输入:setprop debug.MyActivity.enablelog 1
运行时关闭log: 在终端输入:setprop debug.MyActivity.enablelog 0

附:Log.isLoggable(TAG, log.DEBUG) //这个函数表示通过setprop设置的level需要小于DEBUG,值才为True。(默认setprop配置的值是INFO,INFO>DEBUG所以你不配置时,值为false的),通过setprop log.tag. 通过设置属性的方式来改变默认level,也可以将这些属性按照log.tag.=的形式,写入/data/local.prop中;

Info:例如一些运行时的状态信息,这些状态信息在出现问题的时候能提供帮助。
Warn:警告系统出现了异常,即将出现错误。
Error:系统已经出现了错误。

注:Info、Warn、Error等级的Log禁止作为普通的调试信息使用,这些等级的Log是系统出现问题时候的重要分析线索,如果随意使用,将给Log分析人员带来极大困扰。请参考前面的等级介绍合理使用。

注2:禁止使用new Exception(“print trace”).printStackTrace()或者Log. getStackTraceString(Exception)方式打印普通调试信息,因为这种方式打印Log非常消耗系统资源。此种方式打印Log一般只出现try..catch某个异常使用。

注3:Log的tag命名,使用Activity名称或者类、模块的名称,不要出现自己的姓名拼音或其他简称。在c++/c代码中调用ALOGD等宏函数,参数没有传入tag,需要在文件头部#define LOG_TAG”YOUR_TAG_NAME”。

注4:Log的内容,不要出现公司名称、个人名称或相关简称,Log内容不要出现无意义的内容,如连续的等号或星号或连续的数字等,Log内容要方便其他分析Log的人员查看。

注5:Log输出的频率需要控制,例如1s打印一次的Log,尽量只在eng版本使用,user版本如需开启,请默认关闭,通过设置setprop命令来开启。

三、使用方法

c++、c 层输出log:

#include <cutils/log.h>
ALOGV(), ALOGD(), ALOGI(), ALOGW(), ALOGE()

Java层输出log:
import android.util.Log
Log.v(String tag, String msg), Log.d(String tag, String msg),
Log.i(String tag, String msg), Log.w(String tag, String msg), Log.e(String tag, String msg)

四、log显示格式

log示例:I/SysInfoService( 488): SysInfoWorkThread running
等级/TAG(PID) :消息

五、过滤

logcat消息过滤
logcat -c 清除log
logcat -s TAG:D -v [process只显示pid] [tag 只显示 priority/Tag] [thread 显示process:thread and priority/tag]
[raw只显示message][time显示date-time-priority/Tag PID ][long 将元数据和消息分行]

六、Java核心库打印

Java核心库在Android工程的\libcore\luni\src\main\java目录下。
在Android的java核心库中是无法使用Logcat打印的,因为Android的java层要使用Java库,即Java库是Android的Java运行的前提,所以。。。

经过调试,发现其实运用Java的Logger可以很简单的实现(或许Android已经做了处理),在adb logcat中输出。好了,演示一下。

引入包
import java.util.logging.Logger;
static Logger logger = Logger.getLogger(“mytag”);
logger.info(“blala”);
然后在adb logcat直接输出就行了。标签是mytag

Android 打印函数调用栈

发表于 2016-05-26 | 更新于 2019-03-08 | 分类于 Android

0. ActivityThread

StackTraceElement st[]= Thread.currentThread().getStackTrace();  
for(int i=0;i<st.length;i++)  
    System.out.println(i+":"+st[i]);  

1. Java层打印函数调用栈的方法

方法1:

StackTraceElement[] stes = new Throwable().getStackTrace();
if(stes.length >= 1)
{
  for(int i = 1; i < stes.length; i++)
  {
    Log.d(TAG, "File:" + stes[i].getFileName() + ", Line: " + stes[i].getLineNumber() + ", MethodName:" + stes[i].getMethodName());
  }

  for(StackTraceElement elem : stes)
  {
    System.out.println(elem.getClassName() + " " + elem.getMethodName());
  }
}

方法2:

StackTraceElement[] stes = Thread.getAllStackTraces().get(Thread.currentThread());
for(StackTraceElement elem : stes)
{
  System.out.println(elem.getClassName() + " " + elem.getMethodName());
}

方法3:

Throwable throwable = new Throwable(); Log.w(LOGTAG, Log.getStackTraceString(throwable)); 
或者
Log.d(TAG,Log.getStackTraceString(new Throwable()));

方法3:

java.util.Map<Thread, StackTraceElement[]> ts = Thread.getAllStackTraces();
StackTraceElement[] stes = ts.get(Thread.currentThread());
for (StackTraceElement elem : stes)
{
  Log.d(TAG, "SS ", elem.toString());
}

方法4:

(new Exception()).printStackTrace();
或
Exception ex = new Exception("dingran");
ex.printStackTrace();
备注:此方法打印出的TAG是在W/System.err(4275)中;

方法5:

RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Log.w(TAG, "Called: " + this, here);

2. Native层打印调用栈方法

1、打印C++函数调用栈:

#include <utils/CallStack.h>
CallStack stack;
stack.update();
stack.dump();
LOCAL_SHARED_LIBRARIES += libutils

备注:下面操作是可选操作,但加上去之后会有一些额外的功能;

#define HAVE_DLADDR 1 --> 可以从lib中自己转成C++代码行,不需要手动反编译;
#define HAVE_CXXABI 1 --> 将C++已被name mangling的函数名转化为源文件中定义的函数名;

并在文件frameworks/base/libs/utils/Android.mk中大约105行(LOCAL_SHARED_LIBRARIES)后添加
ifeq ($(TARGET_OS),linux)
LOCAL_SHARED_LIBRARIES += libdl
endif
重新编译push生成的libutils.so到/system/lib/目录下,重启设备;
此外,由于CallStack.dump中使用的LOGD进行的打印,因此需要将后台的Log Level设置为D一下才能出来;

2、打印C函数调用栈:

可以参考CallStack.cpp的实现,通过调用_Unwind_Backtrace完成;

3. Kernel层打印调用栈方法

使用函数dump_stack()来打印出函数之间的调用关系;
另外,使用宏BUG()、BUG_ON(xxxx)、WARN()、WARN_ON()、BUILD_BUG_ON()和函数panic(“foo is %ld\n”,foo)也可以在内核中打印调试信息;
其中,宏WARN_ON()最终会调用函数dump_stack();

HTTP MITM

发表于 2016-04-26 | 更新于 2019-03-08 | 分类于 Network

首先明确一个概念:非对称加密算法

非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。
HTTPS协议中,前面的握手过程,服务器会将公钥发给客户端,客户端验证后生成一个密钥用公钥加密后发送给服务器,成功后建立通信。
通信过程客户端将请求数据用得到的公钥加密后,发给服务器,服务器用私钥解密。服务器用客户端给的密钥加密响应报文,发回给客户端,客户端用自己存的密钥解密。

忽略掉其他例如确定协议和版本号之类的环节,提炼出来的重要环节如下:

http_MITM.jpg

阅读全文 »

Android HAL 模型

发表于 2016-04-26 | 更新于 2019-03-08 | 分类于 Android

前言暂时省略…

Android HAL层模型

直接上图:
Android_HAL.png

1…678

Jin

77 日志
9 分类
113 标签
© 2019 Jin
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Mist v7.0.0