以前开发中的一些记录

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26366149/article/details/79686071
ApplicationThread && H
ActivityThread
ActivityThread 应用程序的入口
ViewRootImpl---->负责View的测量绘制
DectorView --->PhoneWindow的内部类,是一个应用程序程序窗体(Window)中视图的根布局(DectorView是一个FrameLayout)
(DectorView中通常包括两个部分,一个是title布局,一个是内容布局,main.xml就是加载在内容不居中的)
PhoneWindow --->是一个手机窗体,继承于Window
MeasureSpac--->是View的一个内部类,View根据MeasureSpac进行测量(主要方法:getMode(),getSize()
View的MeasureSpac来至于父容器,至于顶层容器DectorView的MesaureSpac 是通过ViewRootImpl
#getRootMeasureSpec()来获取)
ZygoteInit--->类是android系统中Java的入口类 (main)
ServiceManager--->用于管理各种服务-->ServiceManager.getService("activity")
ActivityStack---->ActivityManagerService使用ActivityStack对Activity进行操作
ActivityStackSuperviser--->ActivityManagerService使用ActivityStackSuperviser对Task进行操作
ActivityManagerService继承于ActivityManagerNative
ActivityRecord--->应用端的Activity 在ActivityManagerService中对应的是ActivityRecord
ProcessRecord--->对应进程的数据结构
ZygoteConnection--->是客户端在Zygote进程中的代表
ServiceManager--->比较重要的方法是addService(),checkService()
系统的Service通过添加自己的信息注册到ServiceManager 中,checkService
主要是检查该service是否存在
Instrumentation:Instrumentation 可以把测试包和目标测试应用加载到同一个进程中运行,既然各个
测试代码和空间都运行在同一个就进程中,测试代码也就可以调用这些空间和方法,同时修改和验证这些控件
的一些数据,Android Instrumentation 是Android系统里面控制的方法或者钩子,这些钩子可以在正常的生命周期
外控制Android 控件的运行
LoadApk:可以认为是一个APK 文件的具体类代理
ActivityRecord:代表着Activity进程里面的Activity,是一个Binder对象
ActivityClientRecord:token属性就是ActivityRecord属性,
WindowManager extends ViewManager--->add(),remove(),updateViewLayout()
app_process是一个可执行程序,该程序的主要作用是启动zygote和system_server进程
在ActivityManagerService中每一个进程都对应着一个ProcessRecord 对象
Dual-Screen:双屏幕
===================================
System.currentTimeMillis()获取的是系统时间,是距离1970年1月1日开始计算的一个值;
android.os.SystemClock.elapsedRealtime()获取从设备boot后经历的时间值。


=====================================
Activity的启动过程
Activity::startActivity()--->Activity::startActivityForResult()
-->Instrumentation::execStartActivity()--->开始与ActivityManagerService进行通信
ActivityManagerService::startActivity()--->


所有服务启动完后,调用ActivityManagerService.systemReady(),即系统启动完成在该方法中开始启动应用
通过调用startHomeActivityLocked()方法来启动Launcher应用
Launcher 应用的标志:Intent.CATEGORY_HOME常量,这个其实是一个launchery应用的标志,通过getHomeIntent()获得启动的Launcher 的Intent
一般系统的启动页面的Activity都会在androidmanifest.xml文件中添加这个标志
android.intent.Main=====>决定应用最先启动的Activity
android.intent.category.LAUNCHER===>决定应用是否显示在程序列表里
main与launcher同时设定才有意义
当栈顶中存在的activity为空时,就会去启动category为Home的应用


Launcher启动流程
Zygote--->SystemServer进程-->SystemServer::startOtherService()方法--->ActivityManagerService::systemReady()
-->startHomeActivityLOcked()-->ActivityStackSupervisor的startHomeActivity()-->Activity的启动逻辑
Instrumentation--->


Activity的启动流程分为应用进程端SystemServer进程端
Android 四大组件在启动时,在组件初始化完成后真正启动前,回去判断要启动的四大组件所在的应用进程是否已经启动
(如Activity,若启动的Activity所在的进程已经启动则调用realStartActivityLocked()否则调用strtProcessLocked()
用于启动进程)

启动ActivityManagerService所属的进程
总的流程
ActivityManagerService::startProcessLocked()
Process::start()
Process::startViaZygote()
Process::zygoteSendArgsAndGetResult()


ActivityThread::main()--->通过反射的方式
ActivityManagerNative::getDefault()::attachApplication()
ActivityManagerService::attachApplication()


一、fork()的奇妙之处在于被调用一次会返回两个值,却能返回两次
1、在父进程中fork返回的是新建进程的pid号
2、在新建的进程进程中返回的是0
3、出现错误,返回为0
fork函数将运行的着的程序分为2个(完全一样的进程),每个进程从都启动一个从代码的同一位置
开始执行的线程


======================
ViewRootImpl--->是View得根,但并不是一个View对象
Window --->是一个矩形不可见窗体,里面存放的是可见的View对象
PhoneWindow::DecorView---->DectorView是PhoneWindow的内部类,继承于FrameLayout
DectorView 是整个ViewTree 的顶层View 他是一个FrameLayout 的布局代表整个app应用的布局
一般情况下有标题View和内容View两个子元素,当应用主题为没有标题时,DectorView就只用内容View
小结:DectorView 是顶级View 内部有titlebar 和contentParent 两个元素
contentParent的id是content 二我们设置的main.xml 布局则是contentParent 里面的
子元素,contentParent 就是main.xml文件的父布局
DectorView添加了main.xml文件后,添加的View还是不可见的此时,只是加载了布局
还没有对View进行测量,布局,绘制,在进行这个过程之前,还要把DectorView添加到
Window中(Window是一个不可见的窗体,里面存放着可见的view,也就是说View的显示
要依赖于Window),然后经过一系列的ViewRootImpl#performTraversals的方法在
内部进行测量,布局,绘制三大流程
==================================
每个Activity都有一个Window对象用于描述应用程序的窗体,每个应用程序窗体的内部
又包含一个View对象(DectorView),用于描述应用程序窗口的视图
ViewRootImpl ---》负责渲染视图它调用performTraveals 方法使得ViewTree的三大流程
最后View展现在我们面前
==================================
View的测量流程是从ViewRootImpl#PerformTraceals--->performMeasure()
-->performLayout()------>performDraw()
====================================


===============================================
http://www.cnblogs.com/lzlltmf/p/5906799.html
http://blog.csdn.net/zhgxhuaa/article/details/24584807
SystemServer进程的启动流程
init-->Zygoye--->SystemServer,系统中的其他应用进程的启动是通过SystemServer进程来与
Zygote进程通信fork进程的
ZygoteInit::main()--->ZygoteInit::startSystemServer()-->这里会fork出两个进程
在新建的进程中会执行(因为子进程返回的pid = 0)ZygoteInit::handleSystemServerProgress()
handleSystemServerProcess()-->是为了让这个新建的进程成为真正的系统进程,如把进程中本地socket关闭
(来自与Zygote 从Zygote中继承来的)--->
-->RuntimeInit::zygoteInit():
-->redirectLogStreams():从定向系统输出流
-->commonInit():设置默认的线程异常处理器
-->nativeZygoteInit():初始化ProcessState
-->applicationInit():用抛异常的方式来(invokeStaticMain()),来调用SystemServer::main()
应用进程的启动
ZygoteInit::main()-->runSelectLoop()创建的socket进程
ActivityManagerService::startProcessLocked()
Process::start()
Process::startViaZygote()
Process::zygoteSendArgsAndGetResult()
---->通过socket通信(或者说是轮训的方式)将数据传递到ZygoteInit进程,感觉是写入到文件里面了
runSelectLoop()
index==0表示selcet接收到的是Zygote的socket的事件  
调用ZygoteConnection对象的runOnce方法,ZygoteConnection是在index == 0时被添加到peers的
ZygoteConnection::runOnce()
子进程返回pid=0 调用handleChildProc(),后面的逻辑和handleSystemServerProgress()基本相同
只不过这里调用的是android.app.ActivityThread::main()

============================
Android 中添加的系统服务的浅层理解
1、添加*.aidl文件,manager文件
2、mk文件中local_src_file添加*.aidl文件的位置
3、service模块添加服务
4、systemSerer中开启服务,并添加到ServiceManager中进行管理,并注册对应的Manager
*.aidl文件编译后会生成*.java文件,这个类里面存在两个内部类,
setenforce 0 关闭linux 的SeLinux--- getenforce 获取状态:enforce diable pressive
或者修改service_contexts添加配置service_contexts在源码目录:android\external\sepolicy\service_contexts 
同时还要修改:android\external\sepolicy\service.te 文件
自己写的nightmode 服务
-->添加aidl文件
-->manager文件
-->service文件
-->修改SystemServer.java SystemServerRegistery.java,Context
-->修改framework/base/Android.mk 
SystemServer::startOtherService()-->
Slog.i(TAG, "Nightmodeservice");
            nightModeManagerService=new NightModeManagerService(context);---->NightModeManagerService在Service模块中添加
            ServiceManager.addService("nightmode",nightModeManagerService);

//add nightmode --->在SystemServerRegister 中添加
registerService(Context.NightMode_SERVICE, NightModeManager.class,
        new CachedServiceFetcher<NightModeManager>() {
     @Override
     public NightModeManager createService(ContextImpl ctx) {
         IBinder b=ServiceManager.getService(Context.NightMode_SERVICE);
         return new NightModeManager(ctx,INightModeManager.Stub.asInterface(b));
     }});
在framework 下的Android.mk 文件中添加aidl 文件
分别编译framework service 文件 可能遇到权限检查Setenforce 0
自己添加的aidl 文件要放在mk文件中LOcal_SRC_FILE 后面,自定义的类要实现Parable 接口,还要写这个类的aidl 文件(里面是通的,就是申明一下) 必须要导入,即使在同一个包下,接口类,只需要写aidl文件
在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制。
1、如果要在源码中编译要整编
                你需要把我添加的服务加到系统里面Y:\Code\G08-sunming\C9_flumen_20161230\android\external\sepolicy\service_contexts 
                nightmode                                   u:object_r:nightmode_service:s0
2、我们这边没法整编,都是通过命令让他兼容的setenforce 0,效果是相同的


=================================






java 虚拟机加载类的过程


栈:
堆:
方法区:用来存放已被加载的类信息,常量,静态变量




加载,验证,准备,初始化,卸载
加载阶段   :java.lang.ClassLoader 的loadClass()-->加载二进制字节流
将字节流代表的静态存储结构转化为数据结构
在内存中生成一个代表这个类的java.lang.Class的对象,最为方法区这个类
的各种数据的访问入口(就是类访问静态变量的访问)Class对象不是在java 堆内存中
它比较特殊,虽然是对象,但是存放在方法区(这一切只是数据结构的转换,并没有分配内存)


类的链接阶段:连接阶段是将二进制数据合并到jre中

验证阶段:这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求
并且不会危害虚拟机自身的安全。


准备阶段:对类变量分配 内存并设置变量初始值阶段(Class 变量),这个类变量所使用的内存
将在方法区进行分配

解析阶段:


=========================================================
Activity 的启动过程


ProcessRecord-->对应一个进程
ActivityRecord-->对应一个Activity
ActivityInfo--->对应一个Activity的信息
ResovleInfo---->


startActivity最终是调用到startActivityForResult()但是只有在requestCode>0时才会调用到onActivityResult()
startActivity()-->调用startActivityForResult()时的请求码为-1(这是一个默认值)
Activity::startActivity()-->Activity::startActivityForResult()
-->Instrumentation::execActivity()-->调用到AMS中
ActivityManagerNative::getDefault()-->返回的是一个getDefault()
IBinder b=ServiceManager.getService("activity"); 返回的是ActivityManagerProxy
对象,Proxy 对象是实现了aidl接口的
ServiceManager.addService("activity")方法调用实在SystemServer::startBootstrapService()
--->ActivityManagerService::setSystemProcess()方法中
SystemServiceManager 对象用于实例化这些service对象,而ServiceManager 对象用于管理这些对象


ActivityManagerService::startActivity()-->ActivityManagerService::startActivityAsUser()
-->StackSupervisor::startActivityMayWait()






============================
关于Manager Service Aidl 之间的对应关系
SystemServiceRegistry--->静态代码块中--->SystemServiceRegistry::registerService()
--->在SystemSeviceRegistry中存在两个HashMasp 用于记录字符串(Context中添加的字符串)
--->registerService(String seviceName,Class<T> serviceClass,ServiceFetcher<T> serviceFetcher);
ServiceFeature -->是接口其实现类是CachedServiceFetcher()
事实上Manager 与 Service之间没有必然的联系,如果希望通过Context::getSystemService()的方法来获取一个类似
于ActivityManager的对象,只需要在registerService()中注册,但是通常Manager对象用于包装Service对象,所以
在Manager 的构造方法中通常含有Service的aidl接口对象
=================
Binder 中的代码理解
aidl 生成java 文件的形式
例:
IMusicPlayerService.aidl-->IMusicPlayerService.java
IMusicPlayerService extends IInterface
在IMusicPlayerService 存在两个内部内中Stub,Proxy 类
Proxy 负责代表客户端用于将数据传送到度无端Stub中,
Stub 和 Proxy 都implements IMusicPlayerService ,其中Stub 是一个抽象类,需要对方法进行具体的实现
Proxy 中实现的方法只是将数据传送到Stub中
Stub中的asBinder()--->返回的是IBinder
Stub中的asInterface()-->返回的是IMusicPlayerService接口对象


*.aidl文件都是在编译时都会生成一个接口文件,在接口文件的内部存在两个类,分别是Proxy 和Stub 类,这两个类都实现了
 aidl文件的接口类,并且
 
============================
一个应用程序可能包含多个进程(Process属性)每个进程有唯一一个UID 
进程终止后会被系统收回再次打开应用时会从新分配一个PID号(通常比之前的大)
UID 号是在应用安装后就固定不变的在、data/system/packages.list文件中可以查看到
UID 在Linux 系统中是用户的ID 表明哪个应用运行了这个程序主要用于权限的管理,而在Android中有所不同
Android 是单用户系统(通常是这样)这时UID 被赋予了新的使命,数据共享,为了实现数据共享Android init
是root权限,zygote出的系统systemserver被赋予system 的id 权限降为system 权限


===============================
关于Android 6.0权限问题
ContextCompact.checkSelfPermission()
ActivityCompact.shouldShowRequestPermissionRationale()如果用户拒绝了请求的权限,该方法将返回true
如果设备规范禁止该应用的权限,此方法会返回false
如果用户拒绝了权限的请求并在权限请求系统对话框中选择了Do not ask again ,该方法将会返回false
ActivityCompat.requestPermissions()请求权限


通常权限的请求都放置在Activity 中
 Log.e("test==", android.os.Process.myPid()+"   "+ Process.myUid()+"  "+Binder.getCallingUid());
        super.onResume();
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)){
                Toast.makeText(MainActivity.this, "need permission", Toast.LENGTH_SHORT).show();
            }else{
                ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},5000);
            }
        } else {
            Toast.makeText(MainActivity.this, "has this permission", Toast.LENGTH_SHORT).show();
        }


@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if(requestCode==5000){
        if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
            Toast.makeText(MainActivity.this, "获取到权限", Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(MainActivity.this, "权限被拒绝", Toast.LENGTH_SHORT).show();
        }
    }


=======================
关于AndroidManifest.xml文件的解析
PackageInfo:手机中所有包的信息相当于从AndroidManifest.xml文件中收集到
的所有信息
PackageItemInfo--是ApplicationInfo ComponentInfo InstrumentationInfo
PermissionGroupInfo PermissionInfo的基类
ComponentInfo:是ActivityInfo ServiceInfo ProviderInfo
ResolveInfo--是一个通过解析IntentFilter相对应的intent得到的信息,在它的属性中包含了Activitys Services
Broadcasts Providers,这些属性都包含了这些Intent
===========================
关于Binder 的理解
Binder 是Android中用于进程间通信的(IPC)的重要机制,Binder的架构主要是服务器端,客户端,Binder驱动
Binder服务端:一个Binder服务端实际上就是一个Binder类对象,该对象一旦创建,内不会启动一个隐藏的线程
会接受Binder驱动发送的消息服务端收到消息后会执行Binder对象中的onTransact()函数,并按照函数的参数执行不同
的服务器端代码,onTransact()函数的参数是客户端调用transact()函数的输入
Binder驱动:任意一个服务端被创建时同事会在Binder驱动中创建一个mRemote对象该对象是一个Binder类
客户端访问远程度无端都是通过该mRemote对象
Binder客户端:通过远程服务在Binder驱动中回去mRemote对象的引用,然后调用他的transact()方法向服务端
发送消息
ServiceManager:是ServiceManagerNative对象的封装,IServiceManager也是一个Binder对象
但是获取他的方法是固定的就是通过BinderInternal.getContextObject()获取IBinder对象
可以手写使用获取到的mRemote 对象向服务端中传递数据
private String strcat(){
try{
android.os.Parcel _data=android.os.Parcel.obtain()
android.os.Parcel —reply=android.os.Parcel.obtain()
_data.writeString(x);
_data.writeString(y);
mRemote.transact(1,_data,_reply,0)--->1是一个标志
String result;
result=_replay.readString()
}finally{
_data.recycle()
_replay.recycle()
}
}
在服务端Binder中的onTranstract()方法中接受参数
protected boolean onTransact(int code,Parcel _data,Pracel _reply,int flag){
if(code == 1){
String arg1=_data.readString();
String arg2=_data.readString();
String _result=this.strcat(arg1,arg2);
reply.writeString(_result);
}
}
Bidner服务端实现的方法
public String strcat(String x,String y){
return x+y;
}
=======================================
Binder 中
=======================================
Java 中的类加载
ClassLoader 主要作用就是就是将class文件加载到jvm虚拟机中,程序就可以运行了
获取PATH JAVA_HOME CLASSPATH
echo %PATH%
echo %JAVA_PATH%
echo %CLASSPATH%
Java加载流程
系统自带的加载器
BootStrap ClassLoader:最顶层的加载器,主要加载核心类库,主要加载java/lib/下的jar和class
Extention ClassLoader:扩展的类加载器,主要是加载java/lib/ext/的jar和class文件
Appclass Loader:也称SystemAppClass 加载当前应用的classpath的所有类
三个加载器的加载顺序
Bootstrap ClassLoader,猜测可以用System.getProperty("sun.boot.class.path")修改加载的类路径
Extention ClassLoader extends URLClassLoader System.getProperty("java.ext.dirs")
AppClassLoader extends URLClassLoader System.getProperty("java.class.path")-->就是加载当前项目的bin目录
这也是为什么项目中jar包,要放在bin目录的原因
Bootstrap Extention AppClassLoader分别是他们之间的父类加载器(不是继承关系,通过parent属性设定的)
一个ClassLoader在创建时,没有指定parent,那么parent默认的就是AppClassLoader
Bootstrap ClassLoader由C/C++编写,是虚拟机的一部分,在java代码中无法获取到他们的引用
类加载器加载加载类的过程:
某个类加载器在加载某个类时,loadClass 会先看这个类是不是已经被 loaded 过,没有的话则去他的 parent 去找,如此递归,最后还没有加载就自己去加载,称之为双亲委托
JVM 及 Dalvik 对类唯一的识别是 ClassLoader id + PackageName + ClassName,所以一个运行程序中是有可能存在两个包名和类名完全一致的类的。并且如果这两个”类”
不是由一个 ClassLoader 加载,是无法将一个类的示例强转为另外一个类的,这就是 ClassLoader 隔离
===============================================
Class.forName()与URLClassLoader类加载器
Class.forName()只能加载应用程序中的已经应用的类,并且只能用包名的方式进行引用,不能对一个*.Class文件或不在项目中的文件进行应用
使用URLClassLoader就可以直接根据创建一个单独的.class文件,并且每当重新载入后并实例化后都是最新的方法
File xFile=new File("C:/URLClass");
URL  xUrl= xFile.toURL();
URLClassLoader ClassLoader=new URLClassLoader(new URL[]{ xUrl });
Class xClass=ClassLoader.loadClass("testClass");
Object xObject=xClass.newInstance();
Method xMethod=xClass.getDeclaredMethod("test");
==============================
Android 系统的存储系统
android 的存储系统主要是data mnt storage
/mnt/sdcard--->   /sdcard   /storage/emulated/0/  是相同的目录,他们都是External文件目录
/sdcard是个link文件,链接到/mnt/sdcard的
在sdcard 目录中存在一个Android 的文件夹其就类似于data/data/packaga/目录,只不过它是Android/data/package/


===data:就是我们所说的内部存储
在root的手机中可以打开data文件夹:
/data/data/package/share_prefs--->context.getSharedPrefrences(String name,int mode)获取share_prefs文件夹对应的文件名的SharePreference
/data/data/package/databases
/data/data/package/files --->getFilesDir()
/data/data/package/cache --->getCacheDir()
sdcard目录 Environment.getExternalStorageDirectory()
File file=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"learn.test.com.myapplication");sdcard 中创建自己的目录
context.getExternalCacheDir()-->/storage/emulated/0/Android/data/learn.test.com.myapplication/cache
context.getExternalFilesDir()-->/storage/emulated/0/Android/data/learn.test.com.myapplication/files
context.getDir("sunming.txt1",Context.MODE_PRIVATE)--->创建的目录文件就是在/data/data/package/
应用清除数据是吧/data/data/package/  /storage/emulated/0/Android/data/learn.test.com.myapplication/下的数据清空  
清除缓存数据/data/data/package/cache  /storage/emulated/0/Android/data/learn.test.com.myapplication/cache
在使用sharedPreferenced的时候,将数据持久化存储于本地,其实就是存在这个文件中的xml文件里,
我们App里边的数据库文件就存储于databases文件夹中,还有我们的普通数据存储在files中,缓存文件存储在cache文件夹中,存储在这里的文件我们都称之为内部存储。
==================================
关于Grandle 与 Grandle 插件版本
Plugin version Required Gradle version
1.0.0 - 1.1.3 2.2.1 - 2.3
1.2.0 - 1.3.1 2.2.1 - 2.9
1.5.0 2.2.1 - 2.13
2.0.0 - 2.1.2 2.10 - 2.13
2.1.3+ 2.14.1+
Android Studio 中Grandle 是用来对项目进行构建,Grandle插件用来提供grandle 运行的环境
Android Studio打开一个工程时,首先会读取gradle-wrapper.properties 文件,从而知道这个工程需要哪个版本的gradle,
然后就会去保存gradle的文件夹GRADLE_USER_HOME 去找看存不存在这个版本的gradle,不存在则会去distributionUrl 去下载 
搞清楚了这个流程,现在是不是明白了,为什么第一次打开一个工程会巨慢了吧,因为AS会去下载gradle。为什么我明明下载了gradle,
也指定了gradle的存放目录,可打开的时候还是会去自动下载gradle了,那是因为你没有配对地方。现在回过来看项目配置文件是不是gradle/wrapper/gradle-wrapper.properties 是不是恍然大悟?
build.grandle文件中dependences{compile ""}jar包不再是出现在libs这个文件夹下了,而是出现在最下方的External Libraries中
build.grandle -->classpath 'com.android.tools.build:gradle:1.3.0'是grandle 插件的版本 存在于jcenter仓库由grandle进行下载
grandle 存在于user/.grandle 和Android Studio .grandle 目录下,项目打开时读取gradle-wrapper.properties 文件,当Setting中配置为user local 时,表示使用Android Studio的 .grandle
否则为 user/.grandle 如果gradle-wrapper.properties文件中配置的grandle 文件不存在就去下载
grandle 插件在C:\Program Files\Android\Android Studio1\gradle\m2repository\com\android\tools\build\gradle目录下
====================================
Cookie机制
HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。
这就意味着服务器无法从连接上跟踪会话。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。
当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie
cookie.setMaxAge(Integer.MAX_VALUE);           // 设置生命周期为MAX_VALUE
response.addCookie(cookie);                    // 输出到客户端
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,
服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。
Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。
Session对象是在客户端第一次请求服务器的时候创建的
虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,
Session不能依据HTTP连接来判断是否为同一客户,
因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。
=============================================
对OkhttpClient
 RequestBody formBody=new FormBody.Builder()
                 .add("name","maplejaw")
                 .add("age","18")   
                 .build();
  public static final MediaType STREAM = MediaType.parse("application/octet-stream");
 //构建表单RequestBody
 RequestBody multipartBody=new MultipartBody.Builder()
                .setType(MultipartBody.FORM)//指明为 multipart/form-data 类型
                .addFormDataPart("name","maplejaw") //添加表单数据
                .addFormDataPart("age","20") //添加表单数据
                .addFormDataPart("avatar","111.jpg",RequestBody.create(STREAM,file)) //添加文件,其中avatar为表单名,111.jpg为文件名。
                .addPart(..)//该方法用于添加自定义Part,一般来说以上已经够用
                .build();
================================
Activity 生命周期的各个方法作用
onCreate:主要是数据的初始化工作
onStart : 显示activity 界面,此时用户对activity 可见但是不可交互
onResume:用户可以进行交互
onPause :用户可见但不可交互
onStop :界面不可见
onDestory:destory
===================================
uid、appid和user id。
在多用户系统中,user id 带便着当前登录的用户,不支持多用户的系统中user id 为0 
,uid 是应用安装时分配的,appid 
uid = user id * 100,000  + appid(其中,0<=appid<100,000)
Android 在安装一个应用程序时就会给该应用分配一个uid 其中系统进程的uid 在10000以下,第三方应用的uid
是从10000开始分配
=============================
Activity::attach()===>实例化window-->PhoneWiindow;
在attach()方法中activity window 是PhoneWindow对象,并且设置了Window.Call回调
而且activity中持有Window的引用,意味着在调用CallBack接口方法的时候,activity可以得到相应的
回调,并且activity 可以通过window 对象的属性去操作view对象
Activity::setContentView()-->mContentParent就是FrameLayout;调用Activity::setContenView()
Activity::addContentView()会触发回调Activity::onContentChanged()
Activity::installDecor()就是类似于整个界面的View的根,形成主要View的结构
Activity::generateLayout()根据feature,flag 等加载不同的View,这个被加载的View中包含了一个
id 为 com.android.internal.R.id.content的FrameLayout 对象
---mContentView--->contentParent--->activity_main.xml
mDector |--状态栏
|--操作栏(ActionBar)
-========================
================OTHERS==========
Java 反射
http://blog.csdn.net/qq_17250009/article/details/70854631
constructor.setAccessible(true);设置在调用构造器时不用进行权限检查,private 时不用进行权限检查
method.setAccessible(true)
INotificationManager.Stub.asInterface(ServiceManager.getService("notification"))
ActivityThread::performLauncherActivity()-->Activity::attach()-->实例化PhoneWindow()
ActivityThread::performResumeActivity()-->Activity::onResume()--->会创建DecorView
PhoneWindow的作用就是操作View,Activity调用findViewById类似的方法都是通过PhoneWindow间接操作View。
如此,DecorView作为View树的顶级视图通过PhoneWindow便和Activity关联了起来。
PhoneWindow也不是直接操作DecorView,中间还隔着个ViewRootImpl。
在WindowManger#addView的过程中,调用了ViewRootImpl#addView。
WindowManager的实现类主要是WindowManagerImpl
===================================
SystemServer进程与应用进程间的通信方式
1、通信方式使用的都是Binder机制
2、SystemServer 持有了ApplicationThread的代理对象用于和APplication 应用进程进行交互
3、应用进程持有了很多的服务代理对象与System Server 进行通信
====================================
Android Window 与View
窗口主要包括:应用程序窗口,子窗口,系统窗口
WindowManager对窗体进行标记(内部类LayoutParam)
Activity中的Token对象
Token 是ActivityRecord的内部静态类,Token extends IApplicationToken.Stub,是一个匿名的
Binder实体类这个Binder 实体会传递给其他进程,其他进程会拿到Token 对象的代理对象
Binder 的两个重要用途,获取到Binder代理端后可调用实体端的函数接口,
一个作用便是在多个进程中标识同一个对象,往往这两个作用是同时存在的
Token 标识了一个ActivityManagerService中的ActivityRecord对象,即间接标识了一个Activity
Token对象的创建与传递:
在启动Activity 时,有ActivityManagerService会创建ActivityRecord 并创建Token对象这个Token 对象
就是ActivityRecord 的引用该Token 可以用来标记这个ActivityRecord 而该ActivityRecord 
可以用来标记Activity
在ActivityStack::startActivityLocked()会调用wms::addAppToken(),Token对象会传递到
WindowManagerService中,并创建AppWindowToken
在ActivityThread::scheduleLunchActivity()会创建ActivityClientRecord对象对象ActivityClientRecord
对象存在这样的Token属性 ActivityClientRecord 代表着本地应用进程的Activity对象
如果Window对象属于某个Activity那么他们的Token 是相同的对象,否则appToken对象就为空
=============================================
zygote的启动:
再linux系统的init进程中通过fork()创建zygote(app_process)进程,通过execve系列的系统调用进入app_process的main函数。
=============================================
关于源码编译后的img文件和刷机
刷机
解锁bootloader
bootloader默认情况下是锁定的。在设备处于FASTBOOT模式,引导程序执行以下命令被解锁。
fastboot oem unlock
烧录镜像
在编译完后,输出目录会生成相应的rom镜像文件,使手机进入fastboot模式,输入以下命令,即可完成刷机。


% cd out/target/product/<device> # (replace <device> with correct value for your device)
% fastboot flash boot boot.img
% fastboot flash system system.img
% fastboot flash userdata userdata.img
你只需要将手机置于fastboot模式下,然后在你编译生成的一大堆*.img文件的地方执行这个明星就行了。
-w 选项清空设备上的/data分区,在第一次完整刷机的时候是必须的,不然可能读取到错误的缓存文件,系统就起不来了。
在这里我下载了Nexus 6p的官方的rom包,我们看看这个文件中的内容是什么? 下面就是脚本文件的内容
fastboot flash bootloader bootloader-angler-angler-02.45.img
fastboot reboot-bootloader
sleep 5
fastboot flash radio radio-angler-angler-02.50.img
fastboot reboot-bootloader
sleep 5
fastboot -w update image-angler-mmb29p.zip
上面几个命令跟bootloader、基带、重新启动有关,我们直接看最下面的命令
fastboot -w update image-angler-mmb29p.zip 这个image-angler-mmb29p.zip又是什么呢?
解开后就是这么几个文件:android-info.txt boot.img cache.img recovery.img system.img userdata.img vendor.img
Fastboot使用方式: fastboot [ <选项> ] <命令>
[]括起来表示这个是可选的.
<>括起来表示这个是必须的.
=========Android UI 优化=============
UI卡顿的原理:
换算关系:60帧/秒-----------16ms/帧
准则:尽量保证每次在16ms内处理完所有的CPU与GPU计算、绘制、渲染等操作,否则会造成丢帧卡顿问题。
针对Android系统的设计我们还需要知道另一个常识;虚拟机在执行GC垃圾回收操作时所有线程(包括UI线程)都需要暂停,
当GC垃圾回收完成之后所有线程才能够继续执行(这个细节下面小节会有详细介绍)。也就是说当在16ms内进行渲染等操
作时如果刚好遇上大量GC操作则会导致渲染时间明显不足,也就从而导致了丢帧卡顿问题。
I卡顿常见原因:
人为在UI线程中做轻微耗时操作,导致UI线程卡顿;


布局Layout过于复杂,无法在16ms内完成渲染;


同一时间动画执行的次数过多,导致CPU或GPU负载过重;


View过度绘制,导致某些像素在同一帧时间内被绘制多次,从而使CPU或GPU负载过重;


View频繁的触发measure、layout,导致measure、layout累计耗时过多及整个View频繁的重新渲染;


内存频繁触发GC过多(同一帧中频繁创建内存),导致暂时阻塞渲染操作;


冗余资源及逻辑等导致加载和执行缓慢;


臭名昭著的ANR;
UI卡顿分析解决方法:
使用HierarchyViewer分析UI性能
使用GPU过度绘制分析UI性能
颜色 含义
无色 WebView等的渲染区域
蓝色 1x过度绘制
绿色 2x过度绘制
淡红色 3x过度绘制
红色 4x(+)过度绘制
我们需要依据此颜色分布进行代码优化,譬如优化布局层级、减少没必要的背景、暂时不显示的View设置为GONE而不是INVISIBLE、
自定义View的onDraw方法设置canvas.clipRect()指定绘制区域或通过canvas.quickreject()减少绘制区域等。
Android 工具:
Lint 是Android Studio 提供的 代码扫描分析工具,它可以帮助我们发现代码结构/质量问题,
同时提供一些解决方案,而且这个过程不需要我们手写测试用例。
类似上面logcat打印一样,触发垃圾回收的主要原因有以下几种:
GC_MALLOC——内存分配失败时触发;
GC_CONCURRENT——当分配的对象大小超过一个限定值(不同系统)时触发;
GC_EXPLICIT——对垃圾收集的显式调用(System.gc())
GC_EXTERNAL_ALLOC——外部内存分配失败时触发;
这种不停的大面积打印GC导致所有线程暂停的操作必定会导致UI视觉的卡顿,
所以我们要避免此类问题的出现,具体的常见优化方式如下:
AndroidStudio--->Tools--->Android--->Android Devices Monitor  DDMS->Allocation Tracker标签打开一个新窗口
发生ANR 时候anr 相关的文件 adb pull /data/anr/traces.txt ./


既然每个Android应用程序都执行在自己的虚拟机中,那了解Java的一定明白,每个虚拟机必定会有堆内存阈值限制
(值得一提的是这个阈值一般都由厂商依据硬件配置及设备特性自己设定,没有统一标准,可以为64M,也可以为128M等;
它的配置是在Android的属性系统的/system/build.prop中配置dalvik.vm.heapsize=128m即可,
若存在dalvik.vm.heapstartsize则表示初始申请大小),
也即一个应用进程同时存在的对象必须小于阈值规定的内存大小才可以正常运行。


查看应用的memory 信息: adb shell dumpsys meminfo -a packagename 关注几个重要的Object个数即可判断一般的泄露
前面也提到过应用的内存分配是有一个阈值的,超过阈值就会出问题,这里我们就来看看这个问题—–内存溢出(OOM–OutOfMemoryError)。
内存溢出的主要导致原因有如下几类:
应用代码存在内存泄露,长时间积累无法释放导致OOM;
应用的某些逻辑操作疯狂的消耗掉大量内存(譬如加载一张不经过处理的超大超高清图片等)导致超过阈值OOM;
可以发现,无论哪种类型,导致内存溢出(OutOfMemoryError)的核心原因就是应用的内存超过阈值了。
=============================
putty :用于多用户登录linux 系统
beyond:用于文件对比
=======================================
什么是AAR,与JAR区别
*.jar:只包含了class文件与清单文件,不包含资源文件,如图片等所有res中的文件。
*.aar:包含所有资源,class以及res资源文件全部包含
如果你只是一个简单的类库那么使用生成的.jar文件即可;如果你的是一个UI库,
包含一些自己写的控件布局文件以及字体等资源文件那么就只能使用.aar文件。
============================================
/data/system的目录,并且创建了packages.xml, packages-backup.xml, packages.list, packages-stopped.xml等文件。
packages.xml:        是保存了系统所有的Package信息
packages-backup.xml: 是packages.xml的备份,防止在写packages.xml突然断电
packages.list:        保存了系统中已经安装的apk,以及对应的data/data/下面的对应关系
packages-stopped.xml: 用于记录系统中强制停止运行的Package信息
packages-stopped-backup.xml: 是packages-stopped.xml的备份,防止在写packages-stopped-backup的时候突然断电
在apk安装的时候就会为其分配一个UID所以在第一次读取的时候
android:sharedUserId="android.uid.systemui"
===========================================
使用dumpsys 命令来设置开关
每个系统的service 中都会有dump()方法用来打印dump()信息,可以在dump()方法中调用自己类里面定义的dump()方法可答应一些重要信息
并且可以将这些dumpsys 命令携带的参数传递到自己定义的方法中来来作为一种代码控制开关
 例如:dumpsys netpolicy setEnable true 
 其中setEnable true 为两个参数,参数个数为2,第一个为setEnable,第二个为true,谢谢参数会存放在一个数组中,从这个数组中获取该数据
============================================
HandlerThread:是一个持有Loop对象的Thread
Handler发送的消息由谁哪个线程处理是由Loop对象所在的线程决定的,因为Handler发送的消息会被放到Loop中的MessageQueue中
==============================================
systrace 命令抓取:python systrace.py --time=15 -o mynewtrace.html sched gfx input view webview wm am audio video camera hal res  app dalvik rs sched freq idle load sync disk
要等3秒左右,在systrace.html 中的systemserver进程中找到启动的应用关于launcher的启动时间(package:launcher)
=============================================
在app 新建目录病放置一个apk文件用于编译进行平台签名
###############################################################################
# GoogleHome
LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)
LOCAL_MODULE := GoogleHome--->编译后生成文件名
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_BUILT_MODULE_STEM := package.apk
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
#LOCAL_PRIVILEGED_MODULE :=
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_OVERRIDES_PACKAGES := Launcher2 Launcher3
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
#LOCAL_REQUIRED_MODULES :=
#LOCAL_PREBUILT_JNI_LIBS :=
include $(BUILD_PREBUILT)
=========================
1. 所有的ActivityRecord会被存储在mHistory管理;
2. 每个ActivityRecord会对应到一个TaskRecord,并且有着相同TaskRecord的ActivityRecord在mHistory中会处在连续的位置;
3. 同一个TaskRecord的Activity可能分别处于不同的进程中,每个Activity所处的进程跟task没有关系;
=========================
关于Binder,BinderProxy
Binder.java中包含了BinderProxy.class
Java Binder与Native Binder 之间的交互:Binder.cpp中register_android_os_Binder()
Java Binder类和Native层的关系
Java BinderInternal类和Native层的关系
Java BinderProxy类和Native层的关系
Java Parcel类和Native层的关系
============================
SystemUI 的启动过程
1、SystemServer::startCoreService()-->ActivityManagerService::systemReady()-->startSystemUI()
--->启动SystemUIService服务
SystemUIApplication::继承了Application--->onCreate()--->这里会注册INTENT_ACTION_BOOT_COMPLETED
SystemPannel extends SystemUI
Android 系统在对Key 事件进行分发的时候,回先给系统一个处理的机会,即在PhoneWindowManager::interceptKeyBeforeDispatching()进行处理
=================================================================================
关于Systrace 性能分析:主要是进行不同性能的对比
Systrace允许你监视和跟踪Android系统的行为(trace)。它会告诉你系统都在哪些工作上花费时间、CPU周期都用在哪里,
甚至你可以看到每个线程、进程在指定时间内都在干嘛。它同时还会突出观测到的问题,从垃圾回收到渲染内容都可能是问题对象,甚至提供给你建议的解决方案。
设备要求API>=16(Android 4.1)
python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
在Android 4.3及以上的代码中,你可以通过Trace类来实现这个功能。它能够让你在任何时候跟踪应用的一举一动。
在你获取trace的过程中,Trace.beginSection()与Trace.endSection()之间代码工作会一直被追踪。
android 4.3系统上,应用可以使用
     import android.os.Trace;
     Trace.beginSection("TEST");
     Trace.endSection();
添加systrace跟踪,然后通过python systrace.py --app=TEST 指定apk。


framework的java层代码里面添加systrace跟踪方式:
     import android.os.Trace;
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
==============================================================
Log 分析:
I/ActivityManager﹕ Displayed xxx.xxx.xxx/TestActivity: +1s272ms (total +3s843ms) 
第一个时间表示系统接受到打开的intent到TestActivity界面显示出来的时间1.272秒。
第二个时间特殊情况下才会有。例如这种调用流程:A->B(在onCreate立刻finish掉自己,直接跳转到C)->C(TestActivity),
它包含了B页面onCreate处理以及finish的时间。这个时间如果过长,
会导致用户点击跳转后,页面还停留在原来界面,延迟一段时间再跳转。
这种体验很差,用户会觉得卡顿并容易点击多次。很多应用程序的入口页面,都设计成这种情况的跳转。
GPU呈现模式分析(Peofile GPU Rendering tool)
(1). 绿色水平线代表16ms,要确保一秒内打到60fps,你需要确保这些帧的每一条线都在绿色的16ms标记线之下.任何时候你看到一个竖线超过了绿色的标记现,你就会看到你的动画有卡顿现象产生.  
(2). 蓝色代表测量绘制的时间,或者说它代表需要多长时间去创建和更新你的DisplayList.在Android中,一个视图在可以实际的进行渲染之前,
它必须被转换成GPU所熟悉的格式,简单来说就是几条绘图命令,复杂点的可能是你的自定义的View嵌入了自定义的Path. 
一旦完成,结果会作为一个DisplayList对象被系统送入缓存,蓝色就是记录了需要花费多长时间在屏幕上更新视图(说白了就是执行每一个View的onDraw方法,
创建或者更新每一个View的Display List对象).当你看到蓝色的线很高的时候,有可能是因为你的一堆视图突然变得无效了(即需要重新绘制),或者你的几个自定义视图的onDraw函数过于复杂.  
(3). 红色代表执行的时间,这部分是Android进行2D渲染 Display List的时间,为了绘制到屏幕上,Android需要使用OpenGl ES的API接口来绘制Display List.
这些API有效地将数据发送到GPU,最总在屏幕上显示出来.  
(4). 橙色部分表示的是处理时间,或者说是CPU告诉GPU渲染一帧的时间,这是一个阻塞调用,因为CPU会一直等待GPU发出接到命令的回复,
如果柱状图很高,那就意味着你给GPU太多的工作,太多的负责视图需要OpenGL命令去绘制和处理.  
==============================
Systrace:
CPU N C-State:C-0-->RUN MODE 运行模式
  C-1-->STANDBY 就为模式,随时准备投入运行
  C-2-->DORMANT 休眠模式,被唤醒投入运行有一段时间
  C-3-->SHUTDOWN 关闭状态,需要有较长的时间延迟才能进入运行状态,减少耗电
VSYNC:显示了每次Tick Tack的时间大概都在16ms左右
SurfaceFlinger行展示了其函数调用的CPU耗时情况
(如箭头1所指,SurfaceFlinger中的onMessageReceived函数的运行信息)。
=============================
关于Android 系统的Window Activity View 系统


1、WindowManager extends ViewManager
2、Window-->PhoneWindow
3、WindowManagerImpl implements WindowMAnager


关于ViewRootImpl.java
1、ViewRootImpl 是链接WindowManager 和DectorView 的纽带,更广一点说是连接Window 与View 的纽带
2、ViewRootImpl 完成View 的measure layout draw
3、向DectorView 分发用户发起的event 事件,如:按键,触屏等事件
ViewRootImpl 是其他View树的树根,但他不是View 他实现了View和ViewManager之间的通信协议
具体的实现详情在WindowManagerGlobal 这个类中
WindowManager 提供的功能比较简单主要是添加View 更新View 删除View --->通过WindowManagerGlobal 来执行的
在WindowManagerGlobal 中addView()会实例化一个ViewRootImpl 并将Viewt添加到ViewRootImpl 中,在WindowManagerGlobal 
中通过ArrayList 对rootImpl对象进行管理,在WindowManagerGlobal 的内部存在以下几个ArrayList 变量mViews,
mRoots mParams mDyingViews,mViews是存储的是Window 中对应的View mRoots 存储的是Window 对应的ViewRootImpl
mParams 存储的是Window 对应的布局参数,mDyingView 存储的是正在被删除的View 对象
ViewRootImpl 通过setView 方法来更新界面并完成Window 的添加requestLayout() requestLayout最终会调用performTraversals方法来完成View的绘制
Session extends IWindowSession.Stub ::addToDisPlay()--->WindowManagerService::addWindow()
addView大概一个过程如下:WindowManager——>WindowManagerGobal——>ViewRootImpl——>Session——>WindowManagerService
==================
Activity 可以分发事件是因为Activity implements Window.CallBack接口
Window.CallBack::dispatchTouchEvent....这里面有很多事件分发的方法
==================================
Activity启动流程及应用进程的开始
http://blog.csdn.net/yangzhihuiguming/article/details/51722054 --->Activity启动流程(ActivityManagerService 开始)
ActivityStackSupervisor::startActivityMayWait()-->ActivityStackSupervisor::startActivityLocked()
--->ActivityStackSupervisor::startActivityLocked()--->ActivityStackSupervisor::startActivityUnCheckedLocked()
--->ActivityStackSupervisor::resumeTopActivitiesLocked()--->ActivityStack::resumeTopActivityLocked()--->
ActivityStack::resumeTopActivityInnerLocked()-->ActivitySupervisor::startSpecificActivityLocked()(根据Activity所在进程的是否启动,传入不同参数值,启动应用的进程不存在时,创建进程)
---->ActivityManagerService::startProcessLocked()---->ActivityManagerService::startProcessLocked()--->Process::start
---->Process::startViaZygote()-->Process::zygoteSendArgsAndGetResult()--->将参数数据发送到Zygote进程中ZygoteInit::runSelectLoop()--->ZygoteConnection::runOnce()
---->Zygote::forkAndSpecialize("fork 函数的特点在于fork 的返回值有两个在父进程中返回子进程的pid 在自生进程中返回0 ,当返回为<0时候,表示fork 失败,fork 的子进程和父进程共享内存区域")
--->Zygote::handleChildProc()(关闭socket)-->RuntimeInit::zygoteInit()---RunntimeInit::applicationInit()--->RunntimeInit::invokeStaticMain()
--->在该方法中会抛出异常ZygoteInit.MethodAndArgsCaller---->子线程通过异常的逃逸机制通过反射的方法调用ActivityThread启动
--->ActivityThread::main()---ActivityThread::attach()-->ActivityManagerService::attachApplication(IApplication binder 的proxy 对象)
--->ActivityManagerService::attachApplicationLocked()--->IApplication::bindApplication()--->IApplication::handleBindApplication()--->在这里创建了application 对象
--->LoadedApk::makeApplication()--->Instrumentation::newApplication()--->通过反射创建Application对象--->Application::attach()---->返回到LoadedApk::makeApplication()
--->Instrumentation::callApplicationOnCreate()---->Application::onCreate()


在进行ActivityManagerService::attachApplicationLocked()--->ActivtiyStackSupervisor::attachApplicationLocked()--->ActivityStackSupervisor::realStartActivityLocked()
---->IApplication::scheduleLaunchActivity(Binder 间的数据通信)-->ActivityThread::handleLaunchActivity()--->ActivityThread::performLaunchActivity()-->Instrumentation::newActivity()
--->反射创建Activity对象--->ActivityThread::handleResumeActivity()--->ActivityThread::performResumeActivity()--->Activity::onResume()--->


--->Activity::attach()--->在此创建Window对象(PhoneWindow对象)--->创建这个PhoneWindow对象后会设置Window.Callback,WindowCallBack 接口主要存在的是分发事件的方法,如dispatchTouchEvent()
--->在attach()方法中PhoneWindow 对象持有了WindowManager对象,Window 对象通过该WindowManager 对象来控制View对象的添加,刷新,删除。WindowManager extends ViewManager
ActivityThread::performLaunchActivity()--->Activity::attach()--->Activity::setTheme()--->Instrumentation::callActivityOnCreate()--->Activity::performStart()
Instrumentation::callActivityOnRestoreInstanceState()--->Instrumentation::callActivityOnPostCreate()-->
-->方法中调用的这几个方法都是在在这设置好主题,在Activity 的attach()方法中存在FragmentController对象




--->Activity::callActivityOnRestoreInstanceState()--->Activity::performRestoreInstanceState()-->Activity::onRestoreInstanceState()


--->ActivityThread::performLaunchActivity()--->Instrumentation::callActivityOnCreate()---->Activity::performCreate()--->Activity::onCreate()---


这边主要是Fragment 的逻辑
--->在onCreate中调用FragmentController::dispatchCreate()--->FragmentManagerImpl::dispatchActivityCreated()-->FragmentManagerImpl::moveToState()--->
--->FragmentManagerImpl::startPendingDeferredFragments()-->FragmentManagerImpl::performPendingDeferredStart()--->FragmentManagerImpl::moveToState()--->Fragment::onAttach()
--->Fragment::performCreate()--->Fragment::onCreate()--->Fragment::performCreateView()--->Fragment::onCreateView()


ActivityThread::performLaunchActivity()--->Activity::performStart()-->FragmentController::dispatchStart()--->FragmentManagerImpl::dispatchStart()--->Fragment::onStart()
Activity::onPostCreate()--->当Activity 启动完后,会回调这个方法,并且这个方法回调后就可以获取到View 的宽,高
============================================================================
关于Android 系统的UI:http://892848153.iteye.com/blog/1900830
http://blog.csdn.net/lmj623565791/article/details/45022631
AttributeSet.java--->存放的是属性集合的key value 对,这个key value 对是在layout.xml文件中,当value 为应用时获取的是引用的id 值,还要继续进行解析
TypedArray.java---->比AttributeSet.java 简化了获取值得过程
我们在这里定义的属性是声明一个属性的集合里面是每个属性的名称和属性的值得格式
<declare-styleable name="test">
        <attr name="text" format="string" />
        <attr name="testAttr" format="integer" />
</declare-styleable>




TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test);
String text = ta.getString(R.styleable.test_testAttr);
int textAttr = ta.getInteger(R.styleable.test_text, -1);


String attrName = attrs.getAttributeName(i);
String attrVal = attrs.getAttributeValue(i);


int widthDimensionId =  attrs.getAttributeResourceValue(0, -1);
Log.e(TAG, "layout_width= "+getResources().getDimension(widthDimensionId));




只用在onCreate()方法中调用setContentView()方法后系统才会将View 显示在Activity 中,其中根View是mDector,View的树形结构是由ViewRootImpl来负责管理添加的
当我们没有调用setContentView()时,mDector 和 mContentParent描述的信息可以概括为 mDector 是 窗体的顶级视图,mContentParent 是放置窗体内容的容器,
也就是我们 setContentView() 时,所加入的 View 视图树。
当我们没有调用setContentView(),那么DecorView 是在handleResumeActivity()添加的
在ActivityThread::handleResumeActivity()--->PhoneWindow::getDecorView()--->PhoneWindow::installDecor()--->PhoneWindow::generateDecor()
--->




ActivityThread::systemMain()-->用于系统应用的启动
ActivityThread::main()-->第三方应用启动
ActivityThread::attach()-->参数为true 表示是系统应用
ActivityThread::attach()-->参数为false 表示是第三方应用
====================================================
关于Android 主题设计
Theme一般应用于Application和Activity层级,并会继续向下覆盖,这里我们虽然只是设置了Application的theme属性,其下的所有Activity都会使用该主题。
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>
=============================================================
Android Studion的Monitor中显示No Debuggable Application的解决方法
第一种方法,直接Tools - > Android -> Enable ADB Integration active,就OK了。 
第二种情况,就是看一下你的build variants里面,设置的是debug还是release,如果设置的是release,改成debug就OK了。
===========================================================
关于Java 线程池:Java 里面线程池的顶级接口是Executor 但是严格意义来讲Executor 并不是一个线程池,只是一个执行线程的工具真正的线程池接口是是
ExecutorService类
Java 通过Exectors 提供四种线程池
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
线程池为max_value,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);--->支持定时及周期性任务执行
定时: scheduledThreadPool.schedule(new Runnable())  周期性:scheduledThreadPool.scheduleAtFixedRate(new Runnable() )
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();--->有利于FIFO LILO 的操作
重要的类:
ExecutorService: 真正的线程池接口。
ScheduledExecutorService: 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
ThreadPoolExecutor: ExecutorService的默认实现。
ScheduledThreadPoolExecutor: 继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。
1.newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,
那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2.newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。
线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
3.newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,
当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)
能够创建的最大线程大小。
4.newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
===============================
Java 中的阻塞队列:
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
ReentrantLock:可从入锁,ReentrantLock 通过condition条件实现线程之间的通知


方法\处理方式 抛出异常 返回特殊值 一直阻塞 超时退出
插入方法 add(e) offer(e) put(e) offer(e,time,unit)
移除方法 remove() poll() take() poll(time,unit)
检查方法 element() peek() 不可用 不可用


=====================================
Thread.java --->run()方法结束就是线程结束
===================================
https://git-scm.com/book/zh/v1/Git-%E5%88%86%E6%94%AF-%E4%BD%95%E8%B0%93%E5%88%86%E6%94%AF
git 中的分支是基于主分支的
Git 版本控制
工作区,暂存区,版本库
每一次的提交(commit)都是一个版本(log),属于一个分支(branch)
git init
git status
git add filename --->添加到暂存区(. all)
git add file1 file2
git rm filename --->删除文件(. all)
git commit -m "" --->提交到本地仓库
git log
git checkout edfdfdf-->查看以前提交的版本
git checkout master --->回到master最新版本
git checkout -- filename --> 清除对文件的修改
git checkout -- . --> 清除本次的所有修改
git reset --hard HEAD^  HEAD^表示上个版本
git reset --hard id      id 就是log
git diff commit-id-1 commit-id-2 >> diff.txt
git diff branch1 branch2 文件名(带路径)>>diff.txt  //显示指定文件的详细差异
git diff branch1 branch2  >>diff.txt   //显示出所有有差异的文件的详细差异
git diff branch1 branch2 --stat >>diff。txt   //
git branch-->查看分支
git branch branchname-->创建分支
git branch -a
git branch -d branchname--->删除分支
git checkout branchname--->切换分支
===================================
为Doze 设置的iptables 
Chain fw_dozable (0 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10129
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10006
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 99001
   18  2570 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10169
   16  4486 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10182
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1027
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1200
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10001
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10012
   13   780 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10023
    1    60 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10046
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10055
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10176
    6   360 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10179
    0     0 RETURN     esp  --  *      *       0.0.0.0/0            0.0.0.0/0
   50 13244 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 0-9999
   41  2768 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0
Doze 状态下:数组中的数据发生改变时,通过广播来跟新数据,当Doze 状态发生改变时会通过Handle 来发送信息,调用alarm network power等设置doze 状态


Doze 的集中状态:无论处于哪种状态,退出导致回到Active 状态
通过iptables -nvL 查看手机中哪些状态关于网络的规则链,input output dozeable appStandby


BluetoothAdapter.ACTION_STATE_CHANGED
=====================================================
关于冻结应用
休眠是分好几种模式的,不同模式实现方式、耗电量不同
主要有:
1、 state:      Freeze / Low-Power Idle  
ACPI state: S0  
String:     "freeze"  

2、 State:      Standby / Power-On Suspend  
ACPI State: S1  
String:     "standby"  

3、 State:      Suspend-to-RAM  
ACPI State: S3  
String:     "mem"  

4、 
State:      Suspend-to-disk  
ACPI State: S4  
String:     "disk"  
通过/sys/文件系统。查询支持的休眠模式可以cat文件/sys/power/state: 
cat /sys/power/state   
freeze mem  
休眠锁,如果应用持有休眠锁,系统将无法进入休眠模式。
Android设备屏幕暗下来的时候,并不是立即就进入了休眠模式;当所有唤醒源都处于de-avtive状态后,系统才会进入休眠。
Android设备连着adb线到其他设备的情况下,设备是不会进入休眠模式的。
有休眠操作就有唤醒,就需要唤醒源。唤醒源有很多种,在内核注册,比如常用的Power按键。
============================================
aidl 中传递自定义的数据类型时,自定义的数据类型需要实现Parable 接口,和aidl 文件
package android.app;
parcelable WallpaperInfo;
在aidl 中传递接口时,接口的java后缀名要改成aidl,编译时要添加到mk 文件中编译生成对应的java 文件,才能传递数据
编译突然有些非代码错误,重新整编一下或许能解决错误
===================================================
添加一个宏开关
1、在./frameworks/base/core/java/android/provider/Settings.java文件中定义变量:
public static final String LEATHER_SHEATH = "leather_sheath";
2、在frameworks/base/packages/SettingsProvider/res/values/defaults.xml定义一个值:
3、在./frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java文件中:加载默认值
loadBooleanSetting(stmt, Settings.Secure.LEATHER_SHEATH, R.bool.def_leather_sheath);
4、读取方式:
import android.provider.Settings;
Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.LEATHER_SHEATH, 0)
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LEATHER_SHEATH, state);
以上是在framework 添加的文件,也可以直接调用,没有回自己添加
//新增加一个test_set_db,给其赋值
Settings.System.putInt(context.getContentResolver(), "test_set_db", 1);
//新增加一个test_set_db,获取其值
Settings.System.getInt(context.getContentResolver(), "test_set_db", 0)
Settings.Global直接添加字段
=======================================
关于Android 的Wake Lock 锁:在Android 的电源管理系统中扮演着重要的角色。Wake Lock 是一种锁的机制,只要有应用持有这个锁
系统就无法进入休眠,可以被用户态程序和内核获得。这个锁有超时或者没有超时的锁,超时的锁会在时间过后过去后进行自动解锁
如果没有锁,或者超时了,内核就会启动休眠的那套机制来进入休眠 在Android 上层通常通过电源键和wakelock 来使系统唤醒状态
PARTIAL_WAKE_LOCK :保持CPu 运转,屏幕键盘灯可能是关闭的
SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯 
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,允许关闭键盘灯 
FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度 
======================================
对广播源码的解析
1、发送黏性广播要加BROADCAST_STICKY权限  // 发送粘性广播不能有其他权限     // 粘性广播不能发给指定的接收组件  
LocalBroadcastManager 用于在APP内部发送广播
===================================
关于ContentProvider :
getContentReceiver()得到的是ApplicationContentResolver对象 ApplicationContentResolver extends ContentResolver 
ApplicationContentReceiver extends ContentResolver
ContentResolver     ContentProvider两个类中存在相同的方法
ContentResolver在操作数据之前首先调用时acquireProvider()来获得ContentReceiver来(IContentProvider 通过BInder )
 ActivityManagerService.setSystemProcess(); 
        1、通过getService("activity")得到ActivityManagerService的远程Binder;
        2、利用得到的Biner对象通过asInterface()方法,得到这个服务的远程代理;

static public IActivityManager asInterface(IBinder obj) {  
    if (obj == null) {  
        return null;  
    }  
    IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);  //systemserver 进程中调用返回in
    if (in != null) {  
        return in;  
    }  
    return new ActivityManagerProxy(obj);  //其他进程调用返回proxy

==========================================
关于java 中的动态代理对象
java 中的动态代理机制主要是依赖于两个类:InvocationHandler 接口,另一个是Proxy 
每一个动态代理接口必须实现InvocationHandler 接口当我们使用代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke()方法来进行调用
在InvocationHandler这个接口唯一的方法就是invoke方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:  指代我们所代理的那个真实对象
method:  指代的是我们所要调用真实对象的某个方法的Method对象
args:  指代的是调用真实对象某个方法时接受的参数


Proxy这个类的作用就是用来动态创建一个代理对象的类,常用的方法就是newProxyInstance()
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,
那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
通常的做法:

public interface Subject{
public void rent();
public void hello();
}

定义一个类实现该接口
public class RealSubject implements Subject{
   @Override
public void rent()
{
System.out.println("I want to rent my house");
}

@Override
public void hello(String str)
{
System.out.println("hello: " + str);
}
}

我们就要定义一个动态代理类了,前面说个,每一个动态代理类都必须要实现 InvocationHandler 这个接口,
因此我们这个动态代理类也不例外
public class DynamicProxy implements InvocationHandler{
private Object object;
public DynamicProxy(Object object){
this.object=object;
}
public Object invoke(Object object,Method method,Object[] args){
//这个方法会在代理对象调用接口方法的时候被调用
method.invoke(subject,args);
return null;
}
}


 //    我们要代理的真实对象
        Subject realSubject = new RealSubject();


        //    我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
        InvocationHandler handler = new DynamicProxy(realSubject);


        /*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
         * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
         * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
         */
        Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);
        
        System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("world");
============================================
关于Android 的时间传递机制
Activity implement Window.CallBack::dispatchTouchEvent();
PhoneWindow implement Window ===>PhoneWindow::setCallBack()--->就是把activity对象传递过去
 adb shell dumpsys deviceidle enable:开启doze
Settings.Global.putInt(context.getContentResolver(), "bluetooth_security_on_check", 0);
adapter.enable();
Settings.Global.putInt(context.getContentResolver(), "bluetooth_security_on_check", 1);
=================================
Android.mk 文件
该文件对应的目录结构
res
src:package
Android.mk


LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)--->清除本地变量
LOCAL_MODULE_TAGS := optional
LOCAL_PACKAGE_NAME := GMSStatic--->生成模块的名称
LOCAL_CERTIFICATE := platform---->生成平台签名
LOCAL_SRC_FILES := $(call all-java-files-under, src)--->源码目录
include $(BUILD_PACKAGE)--->生成文件类型(这个是apk)
LOCAL_PRIVILEGED_MODULE := true-->priv-app
LOCAL_MODULE_TAGS :=user eng tests optional
user: 指该模块只在user版本下才编译
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译
LOCAL_PATH
当前目录,使用LOCAL_PATH := $(call my-dir)获取当前目录,
LOCAL_PATH不会被include $(CLEAR_VARS) 清理。
LOCAL_MODULE
模块名,在模块编译的时候,LOCAL_MODULE的值会被赋予ALL_MODULE,ALL_MODULE包含了系统所有模块,这些模块会更具系统的其他配置进一步筛选,最终筛选出来的模块会被编译。
LOCAL_SHARED_LIBRARIES:要连接到本模块的共享库。
LOCAL_CERTIFICATE := platform使用平台签名文件签名。
include $(BUILD_STATIC_JAVA_LIBRARY)构建一个静态的jar包
include $(BUILD_PACKAGE)编译生成apk
include $(BUILD_EXECUTABLE)编译生成可执行文件
include $(BUILD_SHARED_LIBRARY)编译生成动态共享库
include $(BUILD_STATIC_LIBRARY)编译生成静态库
LOCAL_JAVA_LIBRARIES
LOCAL_JAVA_LIBRARIES := hello.jar,用于指明依赖的共享Jar包
LOCAL_STATIC_JAVA_LIBRARIES用于指明依赖的静态jar包
WITH_DEXPREOPT:这个变量的使能导致system image中的所有东西都被提前优化(pre-optimized)。这可能导致system image非常大。
WITH_DEXPREOPT := true  
jar包主要依赖的是LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES和LOCAL_STATIC_JAVA_LIBRARIES。
LOCAL_RESOURCE_DIR := \
    frameworks/base/packages/Keyguard/res \
    $(LOCAL_PATH)/res
============================================
在Android 中的Settings里面添加自定义的属性
frameworks/base/core/java/android/provider/Settings.java
public static final String SILVAN_LIU = "silvan_liu";  
public static final String[] SETTINGS_TO_BACKUP ={     
}
PUBLIC_SETTINGS
Intent.FLAG_RECEIVER_REGISTERED_ONLY--->Intent只有注册的才能接受到这个广播
=============================================================================
Android 的doze 状态转换
screen off      30min
Active----------------->InActive--------------->IDLE_PENDING
                      | screen on               30sec                        |1min static
idle mantance<------------------------------------------IDLE
                                 ------------------------------------------->
30min
==============================================
搭建Git 服务器:https://www.cnblogs.com/mengdd/p/4153773.html
服务端设置:
1、安装openssl-server,用于创建SSH 服务
sudo apt-get install openssl-server
使用ps -e |grep ssh:查看服务是否启动
2、创建git 用户,用来管理和运行git 服务
sudo user del -r git--->删除git 用户
sudo adduser git ----->添加git 用户
3、进入git 用户目录下,创建.ssh,然后在.ssh 目录名下创建
登录到git 用户
cd /home/git
sudo mkfir .ssh
cd .ssh
touch authorized_keys
4、将客户端的公钥拷贝到authorized_keys 文件中
cat path/id_rsa.pub >>/home/git/.ssh/authotized_keys目录下
5、安装git-core 也就是git 这是以前的叫法
sudo apt-get install git-core
6、初始化仓库
git -bare init /home/git/test.git--->这个时候git 
对应的仓库地址就是git@hostip:/home/git/test.git
这个命令会生成一个裸仓库,就是是没有工作区的仓库。就是没有源码的目录
客户端设置:
1、 客户端运行ssh-keygen -t rsa 生成秘钥
生成秘钥在.ssh 目录下会有两个文件生成id_rsa 和_id_rsa.pub
id_rsa.pub 是公钥,scp /home/git/.ssh/id_rsa.pub gitServer:/home/git将client上生成的公钥拷贝到gitServer上gitServer 就是主机名,或者ip,gitServer就是主机名
2、服务端把公钥(所有内容复制粘贴过去)添加到authorized_keys文件中后,客户端就能通过路径访问到git仓库了;
3、生成密钥时,会要求你确认保存公钥的位置(默认为~/.ssh/id_rsa),然后会让重复一个密码两次,如果不想在使用公钥的时候输入密码,则留空;
假定hostIp为192.168.1.100,git clone [email protected]:/home/git/test1.git
git 常用命令
git clone [email protected]:/home/git/test.git 本地目录
git remote -v 查看版本库的地址
git log branchname可以显示特定分支的log.
git revert 
git revert HEAD: 撤销最近的一个提交.
     git rm file: 从staging区移除文件,同时也移除出工作目录.
git rm --cached: 从staging区移除文件,但留在工作目录中.
git clean是从工作目录中移除没有track的文件.
git branch: 列出本地所有分支,当前分支会被星号标示出.
git branch (branchname): 创建一个新的分支(当你用这种方式创建分支的时候,分支是基于你的上一次提交建立的).
git branch -d (branchname): 删除一个分支.
git checkout (branchname)   切换到一个分支.
git checkout --<filename>
git remote: 列出remote aliases.
     如果你clone一个project,Git会自动将原来的url添加进来,别名就叫做:origin.
     git remote -v:可以看见每一个别名对应的实际url.
     git remote add [alias] [url]: 添加一个新的remote repo.
     git remote rm [alias]: 删除一个存在的remote alias.
     git remote rename [old-alias] [new-alias]: 重命名.
     git remote set-url [alias] [url]:更新url. 可以加上—push和fetch参数,为同一个别名set不同的存取地址.
===========================
获取Java 程序的调用栈:Thread.dumpStack();  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

猜你喜欢

转载自blog.csdn.net/qq_26366149/article/details/79686071