以前開發中的一些記錄
阿新 • • 發佈:2018-11-12
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()新增的
在ActivityTh
ActivityThread
ActivityThread 應用程式的入口
ViewRootImpl---->負責View的測量繪製
DectorView --->PhoneWindow的內部類,是一個應用程式程式窗體(Window)中檢視的根佈局(DectorView是一個FrameLayout)
(DectorView中通常包括兩個部分,一個是title佈局,一個是內容佈局,main.xml就是載入在內容不居中的)
PhoneWindow --->是一個手機窗體,繼承於Window
MeasureSpac--->是View的一個內部類,View根據MeasureSpac進行測量(主要方法:getMode(),getSize()
#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是否存在
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啟動流程
-->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()新增的
在ActivityTh