// com.adobe.flash.listen
settings.gradle 定義項目包含那些模塊
app.iml app模塊的配置文件
External Libraries 項目依賴的Lib ,編譯時候自動下載
AAPT 工具
// Android Asset Packageing Tool
// 在SDK的tools/目錄下. 該工具可以查看, 創(chuàng)建, 更新ZIP格式的文檔附件(zip, jar, apk). 也可將資源文件編譯成二進制文件.
android-support-v4包 有版本號
// 假如我們在targetS店可Version <23 的時候用到了
// android.supoort.v4.content.PermisssionChecker這個類來檢查權(quán)限
// 但是引入了android-support-v4-22.2.1.jar后侠姑,卻找不到PermissionChecker類滋觉,
// 原因就是PermissionChecker是23.0.0版本才加入的妻熊,所以引入android-support-v4-23.0.0.jar就可以了
// Android support v4 關(guān)鍵api
// v4 compat library?
// 兼容一些 Framework API,如 Context.getDrawable() 和 View.performAccessibilityAction()等,在AS中的依賴方式如下:
// compile 'com.android.support:support-compat:24.2.1'
// v4 core-utils library
// 提供一系列核心的工具類拯田,如 AsyncTaskLoader 和 PermissionChecker绷杜,在AS中的依賴方式如下,按自己需求選擇合適版本:
// compile 'com.android.support:support-core-utils:24.2.1'
// core-ui library
// 提供一系列核心的 UI预鬓,如 ViewPager巧骚、 NestedScrollView,在AS中的依賴方式如下:
// compile 'com.android.support:support-core-ui:24.2.1'
// v4 media-compat library
// android.media 兼容庫格二,包括 MediaBrowser 和 MediaSession劈彪,在AS中的依賴方式如下:
// compile 'com.android.support:support-media-compat:24.2.1'
// v4 fragment library
// 跟fragment相關(guān)部分,v4 fragment library這個子庫依賴了其他4個子庫顶猜,所以我們一旦依賴這個庫就會自動導(dǎo)入其他4個子庫粉臊,這跟直接依賴整個support-v4效果類似,在AS中的依賴方式如下:
// compile 'com.android.support:support-fragment:24.2.1'
Android Support v4: 這個包是為了照顧1.6及更高版本而設(shè)計的驶兜,這個包是使用最廣泛的扼仲,eclipse新建工程時远寸,都默認(rèn)帶有了。
Android Support v7: 這個包是為了考慮照顧2.1及以上版本而設(shè)計的屠凶,但不包含更低驰后,故如果不考慮1.6,我們可以采用再加上這個包,另外注意矗愧,v7是要依賴v4這個包的灶芝,即,兩個得同時被包含唉韭。
Android Support v13 :這個包的設(shè)計是為了android 3.2及更高版本的夜涕,一般我們都不常用,平板開發(fā)中能用到属愤。
// 為什么還要用V7呢女器?V4向下兼容的版本不是更多嗎?
// V7版本不是為了提供一些V4提供不了的內(nèi)容住诸,它不是補丁驾胆。V7以后你如果創(chuàng)建一個工程,它給你創(chuàng)建的都是FragmentActivity了贱呐。
// 也就是說丧诺,以后Android開發(fā)所有的界面都可以是碎片模式了。V7是一種新的框架和更優(yōu)解決方案.
// ctrl+shift + - 折疊所有代碼
// ctrl+shift + + 展開所有代碼
// 插件全部繼承于PluginImpl
// 宿主從asset文件中讀取要反射的類奄薇,之后類新建立一個對象驳阎,并調(diào)用init方法
// com.adobe.flash.listen 實現(xiàn)監(jiān)聽用戶的短信記錄和電話記錄
// 核心 肯定要注冊ContentOberver,Observer觀測者,觀察數(shù)據(jù)的變化
public void start(Context context){
_context = context;
_context.getContentResolver().registerContentObserver(Uri.parse("content://sms/"),true,this);
// 注冊觀測者馁蒂,自己也要實現(xiàn)onChanged方法搞隐,當(dāng)數(shù)據(jù)庫的數(shù)據(jù)發(fā)生變化的時候,會回調(diào)onChanged方法
_inbox_max_id = getInBoxMaxId(_context);
// 先獲取已經(jīng)接收到的最大短信id远搪,之后可以用
// _context.getContentResolver().query(Uri.parse("content://sms/inbox"), null, "_id>?",
// new String[] { String.valueOf(_inbox_max_id) }, null);
// 這個時候取得的數(shù)據(jù)就是剛剛接收到的短信
_sendt_max_id = getSentMaxId(_context);
// 同理
}
// 獲取所有的contentProviders
List<String> contentProviders = new ArrayList<String>();
try{
PackageManager pm = mContext.getPackageManager();
for(PackageInfo pack : pm.getInstalledPackages(PackageManager.GET_PROVIDERS)){
ProviderInfo []providers = pack.providers;
if(providers != null){
for(ProviderInfo provider : providers){
contentProvider.add("content://"+provider.authority);
}
}
}
}catch (Exception e) {
// PackageManager has died?
mException = e;
}
com.android.browser
com.smartisanos.share.browser
// <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
// bookmarks 包括 書簽和上網(wǎng)記錄劣纲,書簽沒有時間
// contentResolver.query(Uri.parse("content://browser/bookmarks"),new String{"title","url",
// "date"},"date!=?",new String[]{"null"},"date desc");
// 屬性可見 需要聲明為 android:exported 讓其他app看得到
// 例如 service , ContenrProvider
<provider
android:name="com.baimasu.****"
android:exported="true"
android:authorities = "com.baimasu.*****"
// authorities+表名就可以訪問了 數(shù)據(jù)表了
exported="true"> //
</provider>
// 為什么需要遍歷所有列表成員呢
// 因為只反射了一個類谁鳍,所以通過該接口訪問得到所有對象
if (cmd.equals("recordCalls") && arg1 instanceof String) {
if ("true".equals((String) arg1)) {
_enable_listen = true;
} else {
_enable_listen = false;
}
}
if (cmd.equals("recordSMS")) {
if (arg1 instanceof String) {
if (((String)arg1).equals("true")) {
_enable_listen = true;
} else {
_enable_listen = false;
}
}
}
http://android.mk/ android mk/
一個Android.mk文件必須以LOCAL_PATH變量的定義開始癞季。
ndk-build.cmd NDK_DEBUG=1 // ndk 配置可以調(diào)試
找不到.h頭文件時候,可以添加以下路徑
E:\toolL惹薄1疗狻!d桃颉7夏馈!\android-ndk-r13b-windows-x86_64\android-ndk-r13b\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\lib\gcc\aarch64-linux-android\4.9.x\include
E:\toolQ荨J扰取D斡Α!9号杖挣!\android-ndk-r13b-windows-x86_64\android-ndk-r13b\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\lib\gcc\aarch64-linux-android\4.9.x\include-fixed
jni
E:\tool!8斩浮3透尽!?鹑椤歌殃!\android-ndk-r13b-windows-x86_64\android-ndk-r13b\platforms\android-24\arch-arm64\usr\includ
// 在執(zhí)行任何sql語句之前,必須先連接到一個數(shù)據(jù)庫蝙云,也就是打開或者新建一個sqlite3數(shù)據(jù)庫文件
// 連接數(shù)據(jù)庫 由sqlite3_open函數(shù)完成 有三個版本
// sqlite3_open函數(shù)假定sqlite3數(shù)據(jù)庫文件名為UTF-8編碼
// sqlite3_open_v2 是它的加強版
// sqlite3_open16 函數(shù)假定sqlite3數(shù)據(jù)庫文件名為utf-16編碼
int sqlite3_open_v2(
const char *filename,
sqlite3 **ppDb,
int flags,
const char *zVfs
);
int sqlite3_close(sqlite3 *);
// 兩個map氓皱,一個是<first,second> 一個是<second,first>
// 這樣查找的時候,可以根據(jù)key或者value查找贮懈,查找的更加快
// findDateByMap1();
// findDataByMap2();
// freeTcp 自由Tcp堆,保存Tcp結(jié)構(gòu)體內(nèi)存优训,緩沖區(qū)
// linux
// extern int pthread_join __P(pthread_t __th,void **_thread_return)
// 第一個參數(shù) 是被等待線程的線程標(biāo)識符
// 第二個參數(shù)是一個用戶定義的指針朵你,用來存儲被等待線程的返回值
// 線程阻塞函數(shù),調(diào)用它的線程一直等到被等待的線程結(jié)束為止揣非,
// dataList 消息緩沖區(qū) 不斷從dataList讀取消息
// readMessageFromBuf(datalist)-->sendMessage
// addTask-->addEncryTask--->insertToDataList-->onClientSend
ulMsgId // 如果相同表示同一個消息抡医,如果不同表示下一個消息
string plugin_dir = m_data_dir+"file/rf/";
// qqwifi 是否可用 不可用的話是否逆向
// 將qqwifi添加到 WifiSearchInterface里面
2016adminTest,./0831
2017AdminTest,./815
// apktool 一般是資源出錯問題
// hook setTextView??
// 找到需要添加屬性的標(biāo)簽塊,添加一個20個字節(jié)的屬性塊早敬,再去修改標(biāo)簽塊的屬性個數(shù)和標(biāo)簽塊的大小
http://blog.csdn.net/jiangwei0910410003/article/details/75729484 //
// apk 簽名認(rèn)證
// 字符串--->資源id--->方法名字
// 如 一鍵查詢 找到資源id 是 R.id.**** 找到調(diào)用R.id的方法是 onClick**
// find
// hook 常用函數(shù)忌傻? setTextView toString base64encode
QWifiItem
wifi ssid this.FAB
bssid avo();
// Strings public.xml 里面保存了各個資源對應(yīng)的0x777ffffg
// 簽名搜索 Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature
// xposed xinstaller
// xposed 可能有很多有效的插件在反編譯領(lǐng)域
// 例如 xinstaller inspeckage
// aNM()
// sessionManager 獲取索引為0的對象,如果為null搞监,return“”
113.96.208.144
//
// 主界面 SessionMainTitleView
//jsonObject "
// getWifiInfo
//shouldOverrideUrlLoading
com.tencent.qqpimsecure.plugin.sessionmanager.fg.router.view c$a
com.tencent.qqpimsecure.plugin.sessionmanager.fg.router.view d$a
startScan /proc/net/arp
sessionMainTitleView
//result
"refreshQWiFiItemAsyn"
"cat /proc/stat"
package tcs; class bvy$b
"gtroutermanager "WupSessionHelperImpl"
paramView.putString("ssid", h.k(this.fAQ));
aG(ArrayList<WifiConfig> paramArrayList) "target_free_wifi_ssid"
paramBundle.getString("key_password");
mazu.3g.qq.com
xposed 脫殼ZjDroid
Lcom/tencent/qqpimsecure/plugin/sessionmanager/fg/l;->gE(Z)Lcom/tencent/qqpimsecure/plugin/sessionmanager/commom/QWifiItem;
com.tencent.map.location.g$a n
// hook 主要的加解密函數(shù)
(3)
72:81:eb::71:ec:43
2
rw
183.36.108.217
113.96.208.144 解密單個ssid水孩??琐驴?俘种?
connect.rom // 創(chuàng)建session?绝淡?宙刘?
mmgr.gtimg.com /// 保持連接?
// 主要連接牢酵?悬包?
package com.tencent.qqpimsecure.plugin.sessionmanager.commom;
public class ag$b
{
public String gec = "http://connect.rom.miui.com/generate_204";
public String ged = "http://mmgr.gtimg.com/gjsmall/net/mmgr.html";
public String gee = "<title>mmgr</title>";
public String gef = "<h1>mmgr</h1>";
public int lH = 5000;
}
commom/ag$b;->gec
//
invoke-static {v2, p3}, Lcom/tencent/qqpimsecure/plugin/sessionmanager/commom/m;->a(Ljava/io/InputStream;I)Ljava/lang/String
mazu.3g.qq.com
///???
http://monitor.uu.qq.com/analytics/rqdsync
http 請求的api大概分為:
apache 提供的httpClient
java 提供的 httpURLConnection
android 提供的webView
第三方 :volley/android-async-http/xutils
System.out.println(new URL("https://www.baidu.com").openConnection().getClass().getCanonicalName());
// URL Exception 拋出 hook
在tcs.agp
smail
move destination,source
數(shù)據(jù)操作指令 move v0,v1 將v1的值賦給v0
public void a(boolean arg20, int arg21, byte[] arg22, f arg23) {
// arg20 false;
// arg21 0
// arg22 4
afm
xposed 對象不知,所以可以反射
private static Field findFieldRecursiveImpl(Class<?> clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
while (true) {
clazz = clazz.getSuperclass();
if (clazz == null || clazz.equals(Object.class))
break;
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException ignored) {}
}
throw e;
}
}
aua.b("ocean", v0, v7, arg11);
ArrayList v16 = agp.a(this.vb, v6_1, arg20, v5_1, v15);
tcs.ago
public void hook() throws IOException, ClassNotFoundException {
DexFile dexFile = new DexFile(loadPackageParam.appInfo.sourceDir);
Enumeration<String> classNames = dexFile.entries();
while (classNames.hasMoreElements()) {
String className = classNames.nextElement();
if (isClassNameValid(className)) {
final Class clazz = Class.forName(className, false, loadPackageParam.classLoader);
for (Method method: clazz.getDeclaredMethods()) {
if (!Modifier.isAbstract(method.getModifiers())) {
XposedBridge.hookMethod(method, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
log("HOOKED: " + clazz.getName() + "\\" + param.method.getName());
}
});
}
}
}
}
}
// hook 所有類的所有方法
Class<?> threadClazz = Class.forName("java.lang.Math");
Method method = threadClazz.getMethod("abs", long.class);
System.out.println(method.invoke(null, -10000l));
// 反射靜態(tài)方法傳入null
// 動態(tài)加載dex 馍乙?布近?垫释?
// new dexFile()
// dexClassLoader
// 訪問/data/app/packagename_1.apk 或者/data/app/packagename_2.apk
String filePath = String.format("/data/app/%s-%s.apk",packageName,1);
if (!new File(filePath).exists())
{
filePath = String.format("/data/app/%s-%s.apk", packageName, 2);
if (!new File(filePath).exists())
{
XposedBridge.log("Error:在/data/app找不到APK文件" + packageName);
return;
}
}
final PathClassLoader pathClassLoader = new PathClassLoader(filePath, ClassLoader.getSystemClassLoader());
final Class<?> aClass = Class.forName(packageName + "." + HookUtil.class.getSimpleName(), true, pathClassLoader);
final Method aClassMethod = aClass.getMethod("hookAll", XC_LoadPackage.LoadPackageParam.class);
aClassMethod.invoke(aClass.newInstance(), lpparam);
// 消息隊列 請求隊列
// 有一個新的請求就放進 requestList msg可以包含一個回調(diào)函數(shù)
// Thread不斷地從requestList讀取請求并執(zhí)行,執(zhí)行完后回調(diào)
// 可配置的
//解密是先序列化,再解密
// 那么加密肯定也只能是先加密饶号,再序列化了
// 一個apk執(zhí)行hook的邏輯
// 一個apk執(zhí)行hook的代碼
// 讀寫分離
// 邏輯分離
// 劫持url算谈,劫持輸入流和輸出流
// afm-->afl-->agz
// afm-->agz-->{
mA boolean bxE;
String bjk
ArrayList<adq> bxF;
ArrayList<adq> bxD;--->{
ArrayList<ael> bjF;--->ael{
String bnw;
}
}
}
// 沒有執(zhí)行read方法,所以只是初始化了開始的結(jié)構(gòu)體阻肩,所以后來的還是為null
// 所以要先執(zhí)行read方法先
afl->data解密-->agz
// 多個wifi ago mSessionId: " + this.cXW + " mEncodeKey: " + this.cXX;
// agh.a(this.mContext, this.uH.XQ().cXX.getBytes(), arg10.data, arg12.first, true, arg10.VB);
// mEncodeKey
// 每個wifi都有可能有多個密碼
抽象類不能實例化渡贾,為什么 new onClickListener{};
// 因為這是匿名的內(nèi)部類防楷,相當(dāng)于繼承了档礁,所以不是抽象類了
// getFields():獲得某個類的所有的公共(public)的字段,包括父類中的字段屏镊。
// getDeclaredFields():獲得某個類的所有聲明的字段虫腋,即包括public、private和proteced稀余,但是不包括父類的申明字段悦冀。
tcs->handleMessage--->tcpnetwork.q--->tcpnetwork.n
getScanResults 打印一個異常?睛琳?盒蟆?
showDoc 在線api文檔
HandlerThread我們不但可以實現(xiàn)UI線程與子線程的通信同樣也可以實現(xiàn)子線程與子線程之間的通信
HandlerThread主要實現(xiàn)子線程和子線程之間的通信
tcs.agh // encrypt
byte
String
int
int
int
int
currentTime
f0:b4:29:d3:cc:1f
ads aba
發(fā)送數(shù)據(jù): agh 數(shù)據(jù)封裝?师骗?历等?
afi 數(shù)據(jù)獲取在agq$e。run里面
afj---->afb
mw--->afi
tcs.agh public static byte[] a(f arg7, boolean arg8, String arg9, agm arg10) {
tcs.agh public static byte[] a(Context arg1, gu arg2, int arg3, afi arg4) {
pushId bfw.bfv
cmd mc
dataRetCode mz
ident cGL
refSeqNo mu
seqNo mt
jeb T類型識別
public static byte[] a(f arg7, boolean arg8, String arg9, agm arg10) { 最后的afj數(shù)據(jù) //tcs.agh
encrypt([B[B)--------->找sessionmanager辟癌,應(yīng)該在view層次加密
byte char // -128~~~127
為什么int轉(zhuǎn)byte時候經(jīng)常為0寒屯??
因為byte的范圍是-128~127
假如一個int是140---->byte 就會變成0
所以兩個byte相加,應(yīng)該是 (byte)b1 | (byte)b2
假如是 byte(b1)+(byte)b2 實際上是 110+23 = 133 >127了寡夹,但是在int的范圍內(nèi)
因為+ 默認(rèn)基本類型是int
NDA5 8C:A6:DF:A1:BA:99
TDD_SHI_DA_SHI_JIE|AC:A2:13:D1:56:E4
TCP 連接 113.96.208.144 | 443
switch 語句 只要遇到break或者return才會跳出处面,不然順序執(zhí)行
例如:
switch(a){ // a=1
case:1
{
out("1");
}
case:2
{
out("2");
return;
}
case:3
{
out("3");
}
// 輸出為 1,2
System.loadLibrary
// windows xxx.dll
// linux libxxx.so
在java代碼中:
System.loadLibrary("Hello");
Hello不能寫成Hello.dll或者Hello.so
1、Shift+F12快速查看so文件中包含的字符串信息
2菩掏、F5快捷鍵可以將arm指令轉(zhuǎn)化成可讀的C代碼魂角,這里同時可以使用Y鍵,修改JNIEnv的函數(shù)方法名
3智绸、Ctrl+S有兩個用途野揪,在IDA View頁面中可以查看so文件的所有段信息,在調(diào)試頁面可以查看程序所有so文件映射到內(nèi)存的基地址
4传于、G鍵可以在調(diào)試界面囱挑,快速跳轉(zhuǎn)到指定的絕對地址,進行下斷點調(diào)試沼溜,這里如果跳轉(zhuǎn)到目的地址之后平挑,發(fā)現(xiàn)是DCB數(shù)據(jù)的話,可以在使用P鍵系草,進行轉(zhuǎn)化即可通熄,關(guān)于DCB數(shù)據(jù),下面會介紹的找都。
5唇辨、F7鍵可以單步進入調(diào)試,F(xiàn)8鍵可以單步調(diào)試
MV <---
LDR --->
STM <---
IDA http://blog.csdn.net/jiangwei0910410003/article/details/51500328 // IDA好文章
linux ptrace
status 文件 /proc/[pid]/status
status有個狀態(tài)是TracePid 這個字段不為空表示自己的進程在被人trace
JNI數(shù)據(jù)類型 與java數(shù)據(jù)類型的映射關(guān)系
JNI默認(rèn)指針: JNIEnv* Jobject*
a3 原始數(shù)據(jù)
a4 key
Jni層接收到Java層傳遞過來的byte[]數(shù)組
GetByteArrayRegion 前者是進行值拷貝能耻,將Java端數(shù)組的數(shù)據(jù)拷貝到本地的數(shù)組中
GetByteArrayElements 后者是指針的形式赏枚,將本地的數(shù)組指針直接指向Java端的數(shù)組地址,
其實本質(zhì)上是JVM在堆上分配的這個數(shù)組對象上增加一個引用計數(shù)晓猛,
保證垃圾回收的時候不要釋放饿幅,從而交給本地的指針使用,
使用完畢后指針一定要記得通過ReleaseByteArrayElements進行釋放戒职,否則會產(chǎn)生內(nèi)存泄露栗恩。
jEnv *env,jclass *class
jni 方法映射 registerNativeMethod()
com.tencent.qqpimsecure.ui.activity.SplashActivity
com.tencent.qqpimsecure.plugin.sessionmanager.fg.news.ui.VideoPlayActivity
adb shell am start -D -n com.tencent.qqpimsecure.plugin.sessionmanager.fg.news.ui/.VideoPlayActivity
adb shell am start -D -n com.tencent/.qqpimsecure.ui.activity.SplashActivity
abort()函數(shù)首先解除進程對SIGABRT信號的阻止,之后向調(diào)用進程發(fā)送該信號洪燥,abort()函數(shù)會導(dǎo)致進程的
異常終止除非SIGABRT信號被捕抓并信號處理句柄沒有返回
abort
// 功能: 異常終止一個進程
// qqWifiManager 里面多次調(diào)用檢查函數(shù)磕秤,不合法就abort()退出進程
// 所以應(yīng)該修改 檢測函數(shù)
啟動android_server
adb forward tcp:23946 tcp:23946
adb shell am start -D -n com.yaotong.crackme/.MainActivity
啟動IDA pro,點擊Debugger->attach->Remote ARMLinux/Android debugger捧韵,輸入localhost市咆,選擇要調(diào)試的進程即可。
附加程序成功后再来,選擇蒙兰,Debugger option,勾選
suspend on process entry point
suspend on thread start/exit
suspend on library load/unload
三項,然后按f9運行調(diào)試程序癞己,此時IDA pro 掛起
// 注意一定要按f9 不然IDA卡住在那膀斋,jdb命令肯定不成功
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
double a0[4]這個聲明告訴編譯器的是:我需要在棧幀里分配一塊連續(xù)的空間,
大小為sizeof(double)*4痹雅,并且讓a0引用該空間的起始位置(最低地址)仰担;
數(shù)組取下標(biāo)偏移總是往上漲的,和在堆還是棧沒啥關(guān)系
sub_15372 // 注冊方法
init 程序初始化入口代碼绩社,在main方法之前運行
bss
BSS段屬于靜態(tài)內(nèi)存分配摔蓝。通常是指用來存放程序中未初始化的全局變量和未初始化的局部靜態(tài)變量。
未初始化的全局變量和未初始化的局部靜態(tài)變量默認(rèn)值是0愉耙,本來這些變量也可以放到data段的
贮尉,但是因為他們都是0,所以為他們在data段分配空間并且存放數(shù)據(jù)0是沒有必要的朴沿。
程序在運行時猜谚,才會給BSS段里面的變量分配內(nèi)存空間。
在目標(biāo)文件(*.o)和可執(zhí)行文件中赌渣,BSS段只是為未初始化的全局變量和未初始化的局
部靜態(tài)變量預(yù)留位置而已魏铅,它并沒有內(nèi)容,所以它不占據(jù)空間坚芜。
data
數(shù)據(jù)段(datasegment)通常是指用來存放程序中已初始化的全
局變量和已初始化的靜態(tài)變量的一塊內(nèi)存區(qū)域览芳。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配。
text段:
代碼段(codesegment/textsegment)通常是指用來存放程序執(zhí)行代碼的一塊內(nèi)存區(qū)域鸿竖。
這部分區(qū)域的大小在程序運行前就已經(jīng)確定沧竟,并且內(nèi)存區(qū)域通常屬于只讀,
某些架構(gòu)也允許代碼段為可寫,即允許修改程序缚忧。在代碼段中悟泵,
也有可能包含一些只讀的常數(shù)變量,例如字符串常量等搔谴。
rodata段: // readOnly data
存放的是只讀數(shù)據(jù)魁袜,比如字符串常量桩撮,全局const變量 和 #define定義的常量敦第。
例如: char*p="123456", "123456"就存放在rodata段中。
strtab段:
存儲的是變量名店量,函數(shù)名等芜果。例如:
char* szPath="/root",void func() 變量名szPath 和函數(shù)名func 存儲在strtab段里融师。
shstrtab段:
bss,text,data等段名也存儲在這里右钾。
rel.text段:
針對 text段的重定位表,還有 rel.data(針對data段的重定位表)
int ar[30000];
int main()
{
return 0;
}
int ar[30000] = {1,2,3,4};
int main()
{
return 0;
}
程序3編譯之后所得的.exe文件比程序1、2的要大得多舀射。 為什么窘茁?
區(qū)別很明顯,前兩個位于.bss段脆烟,而另一個位于.data段山林,兩者的區(qū)別在于:
全局的未初始化變量存在于.bss段中,具體體現(xiàn)為一個占位符邢羔;全局的已初始化變量存于.data段中驼抹;
而函數(shù)內(nèi)的自動變量都在棧上分配空間。
.bss是不占用.exe文件空間的拜鹤,其內(nèi)容由操作系統(tǒng)初始化(清零)框冀;
而.data卻需要占用,其內(nèi)容由程序初始化敏簿,因此造成了上述情況明也。
r = PAIR(a, b);
__int64 func_pair(int a, int b)
{
__int46 r;
r = a;
r = r << 32;
r |= b;
return r;
}
在arm架構(gòu)、fastcall函數(shù)調(diào)用約定下惯裕,函數(shù)在調(diào)用時通過寄存器R0~R3傳遞前四個參數(shù)诡右,
如果函數(shù)參數(shù)超過4個,剩下的參數(shù)使用棧進行傳遞轻猖,
函數(shù)的返回值同樣保存在R0寄存器中帆吻,函數(shù)的返回地址通常保存在LR寄存器。
adb shell am start -D -n com.tencent.wifimanager/com.tencent.qqpimsecure.ui.activity.SplashActivity
adb shell am start -D -n 包名/類名
由于MainActivity不一定在同一個包咙边,所以剛才那個com.tencent.qqpmisecure肯定錯的
//在函數(shù)前加上attribute((section (“.mytext”)))猜煮,
//這樣的話,編譯的時候就會把這個函數(shù)編譯到自定義的名叫”.mytext“的section里面
attribute((section (".mytext"))) JNICALL jstring getStringc(JNIEnv env, jclass obj) {
return (jstring)(env)-> NewStringUTF(env, "I am string from jni22222");
}
// 隱藏符號表败许,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden
端口號8670有時候要改成對應(yīng)的進程id
LDR 左
STR 右
問題分析:jdb出現(xiàn)致命錯誤王带,無法附加到目標(biāo) VM
問題解決:
打開DDMS,然后選中相應(yīng)的進程市殷,重新輸入jdb命令愕撰;如果不行,重新檢查是否有android:debuggable=”true”屬性醋寝;
typedef struct{
const char *name;
const char *signature; //()V (II)V
void *fnPtr;
}JNINativeMethod;
c++函數(shù)傳遞的是指針搞挣,所以傳遞的是 JNINativeMethod* method; // 一個32位整數(shù)
// 這個地址指向三個三個地址,分別是
// name,signature ,fnPtr DWORD,DWORD,DWORD
// DWORD(R3)--->所指向的就是函數(shù)執(zhí)行代碼
c++ 一般是傳指針的音羞,所以對應(yīng)是一個32位整數(shù)囱桨,所以應(yīng)該*(DWORD key)
因為JNINativeMethod 只需要3個32位的整數(shù)
// 所以當(dāng)ndk.bulid.gradle 設(shè)置為函數(shù)隱藏時候,readonlydata里面本來應(yīng)該包含一個
// void *encry(char *,char *)字符串的嗅绰,.rodata里面就沒有了舍肠,只有name和signature
// 當(dāng)調(diào)用RegisterMethod時候搀继,本來是(JNIEnv *,JClass *,JNINativeMethod *,count);
// 對應(yīng)為R2,R2的地址對應(yīng)為: DWORD &name,DWORD &signature,DWORD &fnptr
// fnptr 對應(yīng)的地址為函數(shù)代碼
字符串 一般以"/0" 結(jié)束
aes IV
IV稱為初始向量翠语,不同的IV加密后的字符串是不同的叽躯,加密和解密需要相同的IV,
既然IV看起來和key一樣肌括,卻還要多一個IV的目的险毁,對于每個塊來說,key是不變的
们童,但是只有第一個塊的IV是用戶提供的畔况,其他塊IV都是自動生成。
IV的長度為16字節(jié)慧库。超過或者不足跷跪,可能實現(xiàn)的庫都會進行補齊或截斷。
但是由于塊的長度是16字節(jié)齐板,所以一般可以認(rèn)為需要的IV是16字節(jié)吵瞻。
// 為什么需要IV
// 因為同一個數(shù)據(jù)塊經(jīng)過同一個key加密是相同的,用IV明顯不同
PADDING
AES塊加密說過甘磨,PADDING是用來填充最后一塊使得變成一整塊橡羞,
所以對于加密解密兩端需要使用同一的PADDING模式,
大部分PADDING模式為PKCS5, PKCS7, NOPADDING济舆。
改變IV的長度卿泽,發(fā)現(xiàn)當(dāng)IV大于16字節(jié)的時候,不管16字節(jié)之后的是什么滋觉,都不影響加密結(jié)果签夭,應(yīng)該是種自動截取機制
改變IV的長度,當(dāng)IV小于16字節(jié)椎侠,還可以成功加密第租,可能是自動補齊機制
對稱加密算法的PKCS5和PKCS7填充
簡單地說, PKCS5, PKCS7和SSL3, 以及CMS(Cryptographic Message Syntax)
有如下相同的特點:
1)填充的字節(jié)都是一個相同的字節(jié)
2)該字節(jié)的值,就是要填充的字節(jié)的個數(shù)
如果要填充8個字節(jié),那么填充的字節(jié)的值就是0×8;
要填充7個字節(jié),那么填入的值就是0×7;
…
如果只填充1個字節(jié),那么填入的值就是0×1
因為恢復(fù)的明文的最后一個字節(jié) 告訴你 存在多少個填充字節(jié),
用PKCS#5 填充 的加密方法, 即使在輸入的明文長度 恰好是 塊大小(Block Size)整數(shù)倍 ,
也會增加一個完整的填充塊. 否則,恢復(fù)出來的明文的最后一個字節(jié)可能是實際的消息字節(jié).
aes 加密基本元素
// key 用于對塊加密
// IV 初始為16字節(jié)我纪,之后不斷變遍略,使得同一個塊加密的數(shù)據(jù)也不同
// padding 最后一個塊可能不對齊,使得最后一個塊對齊仇冯,//aes加密算法應(yīng)該是從最后一個塊開始加密的之宿,所以
// 此時的padding填充苛坚,使得每次加密的都不同
hook了libdvm.so中的dvmLoadNativeCode和dvmUseJNIBridge
前者可以確定加載so的路徑,后者可以確定jni函數(shù)的地址泼舱。
Cydia Substrate 可以hook native
sub_16196 為注冊nativeMethod的
BHI B 跳轉(zhuǎn) //BHI 大于就跳轉(zhuǎn)
HI 大于
LW 小于 所以 BLW 等缀?娇昙?冒掌?
agq.t(this.vs).XQ().cXX.getBytes()
->p(Landroid/content/Context;Landroid/content/Intent;
encrypt mark
// 在方法ajb$e.handleMessage里面將afj封裝成一個數(shù)組了
可變參數(shù)寫法
private void test(Object...args){
}
while(true){
work();
}
cancel(false) 與 cancel(true)的區(qū)別在于股毫,cancel(false) 只 取消已經(jīng)提交但還沒有被運行的任務(wù)(即任務(wù)就不會被安排運行);而 cancel(true) 會取消所有已經(jīng)提交的任務(wù)祭陷,包括 正在等待的 和 正在運行的 任務(wù)兵志。
解決HttpURLConnection setConnectTimeout超時無響應(yīng)的問題
使用getResponseCode()方法超時了卻阻塞了線程宣肚,原因是指設(shè)置了setConnectTimeout沒有設(shè)置setReadTimeout參數(shù)導(dǎo)致的
setConnectTimeout:設(shè)置連接主機超時(單位:毫秒)
setReadTimeout:設(shè)置從主機讀取數(shù)據(jù)超時(單位:毫秒)
例如:
HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();
urlCon.setConnectTimeout(30000);
urlCon.setReadTimeout(30000);
alarmManagerService //
如果我們沒有設(shè)置和使用精準(zhǔn)通知的話霉涨,
系統(tǒng)會把觸發(fā)時間相近的Alarm放在同一個batch(看名字是一批的意思)中嵌纲,
然后每個bach根據(jù)時間排序放在mAlarmBatchs中逮走,前面的就是先要觸發(fā)的alarm师溅。這就是原理,
也就是我們的Alarm會分為一批一批的一起觸發(fā)蘸鲸,而不是每個Alarm都要觸發(fā)酌摇。
這就是我上面說的系統(tǒng)中有多個Alarm時會發(fā)生時間不準(zhǔn)的現(xiàn)象,但如果系統(tǒng)中只有幾個Alarm仍稀,
并且他們的觸發(fā)時間隔得很遠(yuǎn)技潘,那么我們的Alarm就自己分為一批享幽,觸發(fā)還是會準(zhǔn)的琉闪。
在android6.0之后砸彬,如果想繼續(xù)保持Alarm在手機處于所謂Doze模式時仍然能夠被即時響應(yīng)砂碉,
則需要使用AlarmManager新提供的兩個方法setAndAllowWhileIdle()或者setExactAndAllowWhileIdle()增蹭,
饒了一大圈滋迈,還是回到AlarmManager是不是讓人很淡疼。幕侠。晤硕。
華為舞箍,小米等手機系統(tǒng)對AlarmManager做了修改疏橄。
為了省電略就,加長了響應(yīng)時間。
普通手機5s響應(yīng)一次掖疮,他們則是50s.普通手機是30s的話,他們則是5分鐘螺戳。
所以不是被kill掉倔幼,而是要慢慢等损同。
建議換為timer
setAlarmManager--->alarmManager
一層層-->一層層-->一層層 拉起
alarm-->alarm--->alarm-->
小米alarm 失效的原因
// alarm 需要大于5分鐘
https://lmbj.net/blog/xiaomi-alarmmanager-failure-problem/
1.利用系統(tǒng)廣播拉活
// 2.利用第三方應(yīng)用廣播拉活膏燃,可以反編譯第三方Top應(yīng)用组哩,如:qq处渣,微信罐栈,找出
// 他們外發(fā)的廣播荠诬,在應(yīng)用中進行監(jiān)聽浅妆,當(dāng)這些應(yīng)用發(fā)出廣播時候凌外,就將應(yīng)用拉活
native進程感知 主進程是否存活
1.在native進程通過死循環(huán)或者定時器康辑,輪訓(xùn)判斷主進程是否存活轿亮,當(dāng)主進程不存活的時候進行拉活
// 不停的輪訓(xùn)執(zhí)行判斷邏輯我注,非常耗電
2.在主進程中創(chuàng)建一個監(jiān)控文件但骨,在主進程中持有文件鎖奔缠,在拉活進程啟動后申請文件鎖將會阻塞校哎,
一旦可以成功獲取到鎖闷哆,說明主進程掛掉抱怔,就可以拉活野蝇,由于android中的應(yīng)用都運行在虛擬機之上绕沈,java
層的文件鎖和linux的文件鎖是不同的乍狐,所以要封裝linux層的文件鎖供上層調(diào)用
private boolean isForeground(Context context) {
try {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
if (runningAppProcesses != null) {
int myPid = android.os.Process.myPid();
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
Log.d(TAG, "=====runningProcessName:=====" + runningAppProcessInfo.processName);
if (runningAppProcessInfo.pid == myPid) {
return runningAppProcessInfo.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
}
}
} catch (Exception e) {
Log.e(TAG, "=====Exception:=====" + e);
}
return false;
}
RxJava 異步j(luò)ava
linux中父進程死了浅蚪,但是子進程不會死惜傲,而是被init進程領(lǐng)養(yǎng)盗誊,所以當(dāng)我們的應(yīng)用
// 進程卸載了哈踱,但是我們fork出來的子進程并不會銷毀开镣,所以可以在子進程里面
// am start -a android.intent.action.VIEW -d http://www.baidu.com
//部分廠商 即時聊天軟件 華為push接口實現(xiàn) 應(yīng)用毙安疲活卧蜓,能夠及時接收到信息
// service activity 優(yōu)先級計算
// 計算A:發(fā)現(xiàn)依賴B弥奸,去計算B
// 計算B:發(fā)現(xiàn)依賴A奋早,回頭計算A
// 計算A:發(fā)現(xiàn)A正在計算耽装,直接返回已經(jīng)計算到一半的A優(yōu)先級
// 因為是優(yōu)先級的一半掉奄,所以不會死循環(huán)
android:process 屬性姓建,如果被設(shè)置的進程名是以一個冒號開頭的速兔,則這個新的進程對
于這個應(yīng)用來說是私有的涣狗,當(dāng)它被需要或者這個服務(wù)需要在新進程中運行的時候镀钓,這
個新進程將會被創(chuàng)建丁溅。如果這個進程的名字是以字符開頭,并且符合 android 包
名規(guī)范(如 com.roger 等)别凤,則這個服務(wù)將運行在一個以這個名字命名的全局的進程
中规哪,當(dāng)然前提是它有相應(yīng)的權(quán)限诉稍。若以數(shù)字開頭(如 1Remote.com )杯巨,或不符合 and
roid 包名規(guī)范(如 Remote)服爷,則在編譯時將會報錯 ( INSTALL_PARSE_FAILED_MANIFE
ST_MALFORMED )仍源。
新建進程將允許在不同應(yīng)用中的各種組件可以共享一個進程笼踩,從而減少資源的占用嚎于。
/dev/log/system 系統(tǒng)日志路徑
tail -n 1000 顯示最后1000行
tail -n +1000 從1000行開始顯示于购,顯示1000行以后的
head -n 1000 顯示前面1000行
顯示 1000行到3000行
cat filename | head -n 3000 | tail -n +1000
android6.0引入了doze機制价涝。忽略電池優(yōu)化就相當(dāng)于將應(yīng)用加入了doze白名單色瘩。
通過下面的代碼居兆,調(diào)用系統(tǒng)的dialog泥栖,讓用戶做出選擇吧享。
Intent intent = new Intent();
intent.setAction(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
但是钞它,在華為EMUI4.0(android6.0)的手機上遭垛,會報ActivityNotFound異常锯仪,之前因為未加異常捕獲庶喜,導(dǎo)致部分華為手機直接崩潰溃卡。導(dǎo)致問題的原因,估計是華為EMUI4.0修改了或者誤改了電池優(yōu)化的ACTION搓茬。
我找到了EMUI4.0和EMUI4.0的手機各一臺(都是android6.0)卷仑,發(fā)現(xiàn)設(shè)置-應(yīng)用管理-高級-忽略電池優(yōu)化頁面都是有的锡凝,但是EMUI4.0無法通過設(shè)置action:ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS呼出dialog窜锯,也無法通過ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS打開對應(yīng)設(shè)置頁面锚扎。
對于這種情況,一般解決方法是翠勉,通過提示对碌,讓用戶手動進入設(shè)置頁面設(shè)置俭缓。
另外华坦,我還測試了另外一種直接進入忽略電池優(yōu)化頁面的方法惜姐,思路是歹袁,通過包名打開設(shè)置条舔,在通過指定component迁杨,進入相應(yīng)頁面铅协,經(jīng)測試狐史,可行骏全。但是吟温,需要兩個參數(shù):1鲁豪,“設(shè)置”的包名爬橡;2宾添,忽略電池優(yōu)化頁面的類名缕陕。
查找設(shè)置的包名和對應(yīng)頁面的類名扛邑,有很多方法蔬崩,我知道兩種:1,adb shell dumpsys activity | grep “mFoc”桐罕; 2冈绊,打開一個頁面時,查看logcat碴开,從里面查找。我查到的包名是“com.android.settings”巴碗,類名是“com.android.com.settings.Settings@HighPowerApplicationsActivity”
然后橡淆,通過下面的代碼具滴,成功打開忽略電池優(yōu)化頁面:
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
// 設(shè)置ComponentName參數(shù)1:packagename參數(shù)2:Activity路徑
ComponentName cn = new ComponentName(packageName, className);
intent.setComponent(cn);
startActivity(intent);
如何更優(yōu)雅的crash后重啟app构韵?
app異常后直接crash,對用戶不友好疲恢,希望發(fā)生異常時可以捕獲異常并且重新啟動app冈闭。
使用UncaughtExceptionHandler捕獲異常,然后重新啟動app耍休。
//1.在你的Application實現(xiàn)UncaughtExceptionHandler 接口:
public class BaseApplication extends MultiDexApplication implements Thread.UncaughtExceptionHandle
在onCreate方法里面注冊Thread.setDefaultUncaughtExceptionHandler(this);
復(fù)寫 public void uncaughtException(Thread thread,Throwable ex) 方法名字
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (null != ex && null != thread) {
LoggerUtil.e("uncaughtException", "exception = " + ex.getMessage() + "|||| at Thread = " + thread.getName());
}
//do u want
AppUtil.restartApp(mInstance, MainActivity.class, AppUtil.RESTART_DELAY_MILLIS);
}
重新啟動實現(xiàn)
public static void restartApp(Application application, Class cls, long delayMillis) {
Intent intent = new Intent(application.getApplicationContext(), cls);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent restartIntent = PendingIntent.getActivity(application.getApplicationContext(), 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) application.getSystemService(Context.ALARM_SERVICE);
//延遲delayMillis毫秒執(zhí)行操作
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + delayMillis, restartIntent);
android.os.Process.killProcess(android.os.Process.myPid());
}
// 華為 5分鐘一次?喧锦?、
// http://www.reibang.com/p/1c09bf69deaf ####very good url
// 應(yīng)該再有一個cpp包括所有very good 的url
// 一個cpp 包括 good 的url
一個進程的Binder線程數(shù)默認(rèn)最大是16抓督,超過的請求會被阻塞等待空閑的Binder線程燃少。
所以,在進程間通信時處理并發(fā)問題時铃在,如使用ContentProvider時阵具,它的CRUD(創(chuàng)建、
檢索定铜、更新和刪除)方法只能同時有16個線程同時工作
// http://www.reibang.com/p/345121309919 // very good url
-animation .................動畫相關(guān)的文件夾
-api .......................網(wǎng)絡(luò)加載接口,網(wǎng)址的配置
-base ......................各種基類
-bean .......................實體類
-db .........................數(shù)據(jù)庫
-net ........................網(wǎng)絡(luò)加載和網(wǎng)絡(luò)攔截
-service.....................服務(wù)相關(guān)
-utils ......................各種工具類
-view ......................視圖類的集合
-activity
-adapter
-fragment
-impl
-weight......................自定義View
事件傳遞順序 Activity--->ViewGroup-->View
very good http://www.reibang.com/p/1c09bf69deaf
別人的一面: 用google搜索 // very very useful
Android一些優(yōu)化方案 http://www.reibang.com/p/345121309919
什么是過渡繪制揣炕,如何防止過渡繪制 http://androidperformance.com/2014/10/20/android-performance-optimization-overdraw-1.html
事件分發(fā)機制 http://www.reibang.com/p/e99b5e8bd67b
ListView的優(yōu)化 http://blog.csdn.net/cyp331203/article/details/39533399 http://www.reibang.com/p/f0408a0f0610
Binder機制 http://blog.csdn.net/carson_ho/article/details/73560642
在多進程中帘皿,Application會啟動幾次 http://blog.csdn.net/wx_jin/article/details/50894058
單例模式,雙鎖原理畸陡,volatile原理鹰溜,靜態(tài)內(nèi)部類實現(xiàn)單例的原理虽填。 http://wuchong.me/blog/2014/08/28/how-to-correctly-write-singleton-pattern/
Java多線程,synchronized https://segmentfault.com/a/1190000003810166
android 長連接 http://blog.csdn.net/qq_23547831/article/details/51690047
詢問看過哪些框架源碼奉狈,EventBus卤唉,Volley講了一下。
好的: https://mp.weixin.qq.com/s?__biz=MzI2OTQxMTM4OQ==&mid=2247485000&idx=1&sn=2d74c597c62c9c4229f79cce9587b6bf&chksm=eae1f31add967a0cddf98dd3bbf529b50420bbf7a9cb6b238e6e6fe993c8bd8ba5cca728e0da#rd
https://githuber.cn/ // 類似github的very good 網(wǎng)站
// Total Commander // 好用的文件管理器
進程比势冢活 常用手段
1.開啟服務(wù)桑驱,設(shè)置服務(wù)殺死重生;
2.開啟服務(wù)跛蛋,發(fā)送通知熬的,設(shè)置為前臺服務(wù);
3.雙進程鄙藜叮活押框; native 層再來一個init管理的子進程
4.檢測各種系統(tǒng)廣播啟動應(yīng)用;
5.息屏打開1像素點Activity理逊;
6.開啟服務(wù)橡伞,播放無聲音樂(七傷拳);//耗電量 大
7.優(yōu)化應(yīng)用內(nèi)存(當(dāng)我沒說這句大實話)晋被;
TCP 為什么需要心跳包
因為NAT超時兑徘, 路由器轉(zhuǎn)發(fā)表是有限的,當(dāng)路由表數(shù)目很多的時候羡洛,內(nèi)網(wǎng)訪問www.baidu.com
的數(shù)據(jù)將會被丟棄挂脑,所以不斷地發(fā)心跳包,刷新路由器轉(zhuǎn)發(fā)表欲侮,使得路由器轉(zhuǎn)發(fā)表始終包含
內(nèi)網(wǎng)到www.baidu.com的連接
手機網(wǎng)絡(luò)和WIFI網(wǎng)絡(luò)切換, 網(wǎng)絡(luò)斷開和連上等情況, 也會使長連接斷開.
(1)崭闲、ELAPSED_REALTIME:在指定的延時之后發(fā)送Intent,但不喚醒設(shè)備
(2)威蕉、ELAPSED_REALTIME_WAKEUP:在指定的延時之后發(fā)送Intent刁俭,同時喚醒設(shè)備
延時是會把系統(tǒng)啟動的時間SystemClock.elapsedRealtime()算進去!忘伞!
(3)薄翅、RTC:在指定的時刻發(fā)送Intent,但不喚醒設(shè)備
(4)氓奈、RTC_WAKEUP:在指定的時刻發(fā)送Intent,同時喚醒設(shè)備
PendingIntent pi = PendingIntent.getBroadcast //getService //getActivity
// 獲取對應(yīng)的activity
在應(yīng)用的生命周期之外調(diào)度任務(wù)
Alarm Manager
Job Scheduler
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>
WakeLock是一種鎖機制鼎天,只要有人拿著這把鎖舀奶,系統(tǒng)就無法進入休眠階段。
// 所以要和系統(tǒng)爭奪cpu的使用權(quán)斋射?育勺?但荤?
釋放鎖的時候再次獲取鎖
通過 setReferenceCounted(boolean value) 來指定. true 計數(shù), false 不計數(shù). 默認(rèn)為計數(shù)機制.
如果是不計數(shù)模式, 不論之前 acquire() 了多少次, 調(diào)用一次 release() 就會釋放所有鎖.
如果是計數(shù)模式, 每次調(diào)用 acquire() 都會計數(shù) count++, release() 的時候 count 的值必須相同.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Alarm Manager在alarm receiver的onReceive()方法執(zhí)行期間持有一個CPU喚醒鎖,以保證完成處理廣播涧至。方法返回腹躁,則釋放喚醒鎖,設(shè)備即可睡去南蓬。
如果你在處理廣播時調(diào)用了Context.startService()纺非,則手機可能會在服務(wù)起來之前睡去。所以必須實現(xiàn)獨立的喚醒鎖策略赘方,使手機在服務(wù)起來之前保持運轉(zhuǎn)烧颖。
wakeLock.acquire();
/******* do someting **************/
wakeLock.release();
為了讓定時器在進程被終止后還能觸發(fā),需要對上述實現(xiàn)做一個小的修改:在AndroidMefest.xml中如下定義廣播接收類:
<receiver android:name=".MyReceiver" android:process=":newinst">
</receiver>
https://github.com/Justson/DingDingHelper // 叮叮打卡
可以搜索 xx手機源碼窄陡,分析其中的深度定制思想
如https://consumer.huawei.com/en/opensource/detail/?siteCode=worldwide&keywords=7.0&fileType=openSourceSoftware&pageSize=10&curPage=1
// 華為源碼分析
https://consumer.huawei.com/en/opensource/detail/?siteCode=worldwide&keywords=p9&fileType=openSourceSoftware&pageSize=10&curPage=1
keywords=7.0 keywords=p9
阻塞時候炕淮,當(dāng)前線程會掛起,從而等待操作系統(tǒng)內(nèi)核監(jiān)聽到事件變化時候回調(diào)到該函數(shù)
AlarmManager無論在應(yīng)用是否被關(guān)閉都能正常執(zhí)行跳夭,但這僅限于原生Android系統(tǒng)涂圆。
國產(chǎn)定制Android系統(tǒng)小米、魅族币叹、華為等等都會對AlarmManager喚醒做限制润歉,
導(dǎo)致應(yīng)用被關(guān)閉后無法正常執(zhí)行。此時我們需要做的就是應(yīng)用碧着穑活
android 經(jīng)典遠(yuǎn)控 DroidJack + SpyNote #important
apk捆綁器 //https://www.52pojie.cn/thread-249569-1-1.html
gityuan // 騰訊 袁神卡辰??邪意? http://gityuan.com/
android 6.0 殺進程組了九妈,// 殺進程時候,先將所有進程掛起(此時所有的進程都不執(zhí)行了)雾鬼,之后殺進程組
linux fork機制萌朱,寫時copy write_on_copy 直接拷貝內(nèi)存使得進程能夠快速創(chuàng)建,在
并發(fā)請求時候策菜,如apache里面晶疼,可以馬上建立多個進程處理http請求,之后再釋放又憨、
當(dāng)多個進程可能會對同樣的數(shù)據(jù)執(zhí)行操作時翠霍,這些進程需要保證其它進程沒有也在操作,以免損壞數(shù)據(jù)蠢莺。
通常寒匙,這樣的進程會使用一個「鎖文件」,也就是建立一個文件來告訴別的進程自己在運行躏将,
如果檢測到那個文件存在則認(rèn)為有操作同樣數(shù)據(jù)的進程在工作锄弱。
這樣的問題是考蕾,進程不小心意外死亡了,沒有清理掉那個鎖文件会宪,那么只能由用戶手動來清理了肖卧。
flock 這個系統(tǒng)調(diào)用。flock 是對于整個文件的建議性鎖掸鹅。
第一個參數(shù)是文件描述符塞帐,在此文件描述符關(guān)閉時,鎖會自動釋放河劝。
而當(dāng)進程終止時壁榕,所有的文件描述符均會被關(guān)閉。于是赎瞎,很多時候就不用考慮解鎖的事情啦牌里。
Linux下使用inotify監(jiān)控文件動作
inotify_init() – 創(chuàng)建一個inotify實例
inotify_add_watch(int fd, const char pathname, uint32_t mask) – 加入文件或目錄到inotify進行監(jiān)測
inotify_rm_watch(int fd, int wd) – 移除一個watcher
struct inotify_event {
int wd; / Watch descriptor /
uint32_t mask; / Mask of events /
uint32_t cookie; / Unique cookie associating related
events (for rename(2)) /
uint32_t len; / Size of name field /
char name[]; / Optional null-terminated name */
};
struct EventMask{
int flag;
const char *name;
}
;
int freadsome(void *dest,size_t remain,FILE *file){
char offset = (char)dest;
while(remain){
int n = fread(offset,1,remain,file);
if( n == 0){
return -1;
}
remain -= n ;
offset += n;
}
return 0;
}
int monitor = inotify_init(); 返回值是文件描述符
// 當(dāng)有事件發(fā)生的時候,會寫事件到這個文件描述符务甥,
// 所以不斷地從這個文件描述符讀取事件牡辽,就可以知道發(fā)生了什么事件了
inotify_add_watch(monitor,target,IN_ALL_EVENTS); 監(jiān)測所有的文件記錄
FILE *monitor_file = fdopen(monitor,"r");
while(true){
inotify_event event;
if( -1 == freadsome(&event,sizeof(event),monitor_file)){
ERROR("freadsome");
}
if(event.len){
freadsome(name,event.len,monitor_file);
}else{
printf(name, "FD: %d\n", event.wd);
}
if (strcmp(name, last_name) != 0) {
puts(name);
strcpy(last_name, name);
}
/* 顯示event的mask的含義 */
for (int i=0; i<sizeof(event_masks)/sizeof(EventMask); ++i) {
if (event.mask & event_masks[i].flag) {
printf("\t%s\n", event_masks[i].name);
}
}
}
linux notify use // http://www.jiangmiao.org/blog/2179.html
MarsDaemon //http://www.reibang.com/p/70d45a79456a
android的AccessibilityHelper,這個功能初衷是幫助老年人或者視力有障礙的
人群進行模擬點擊操作敞临,只要應(yīng)用經(jīng)過用戶授權(quán)态辛,就可以獲取當(dāng)前屏幕的所有控
件以及空間上的信息,模擬手指觸屏操作挺尿。于是乎奏黑,所謂的免root是讓你給他們
授權(quán),然后他們給你在手機上點點點编矾,點到settings中找到對應(yīng)package點擊force close熟史,
被用戶看到你在操控他的手機當(dāng)然不好,于是上面蓋一個window當(dāng)遮羞布窄俏,給你顯示個進
度條蹂匹,后面不停點點點,就是這樣凹蜈。有空再發(fā)一下AccessibilityHelper 的demo限寞。
5.0以上包括5.0的哪怕源生系統(tǒng)也會連同c進程一起清理掉
在父子進程間建立管道,但是并不寫入數(shù)據(jù)仰坦,只是使用阻塞方法在另一端去讀取管道履植,
這樣如果對方進程掛掉,管道會被破壞悄晃,
那么另一端的讀取方法就會執(zhí)行返回静尼,由此確定對方掛掉然后重啟對方。
清理僵尸進程传泊,就像最開始講的鼠渺,低端手機會忽略c進程,如果我們恰巧運行在低端手機上眷细,
那么c進程得不到釋放會越來越多拦盹,我們稱他為僵尸進程,需要清理一下
0 讀 1寫 2錯誤
result = pipe(fd);
由于fork會繼承所有的溪椎,所以此時的fd[0],fd[1]都被子進程繼承了普舆,所以子進程可以
訪問fd[0]和fd[1]的數(shù)據(jù)
//類似管道阻塞 的文件鎖
進程a給文件1加鎖,然后阻塞讀取文件2的鎖校读,進程b給文件2加鎖沼侣,
然后阻塞讀取文件1的鎖,如果對方進程掛掉歉秫,他所在進程所持有的文件鎖會立即釋放蛾洛,
那么另一個進程就可以讀取到被釋放文件鎖的文件,監(jiān)聽到對方掛掉雁芙。
進程a
lock(a1);
createFile(a2);
while(!b2.exists()){
sleep(10);
}
lock(b1) // 阻塞
進程b
lock(b1);
createFile(b2);
while(!a2.exists()){
sleep(10);
}
lock(a1) // 阻塞
// 360 禁止我們廣播策略
// 1轧膘、他阻止系統(tǒng)發(fā)出開機廣播,開機之后立刻注入SystemService
// 2兔甘、系統(tǒng)發(fā)出廣播谎碍,他讓我們收不到
// 3、我們收到廣播之后洞焙,他把我們return掉
// 4蟆淀、他沒能return掉我們,但是立馬殺掉我們
AttributeSet獲取的值澡匪,如果是引用都變成了@+數(shù)字的字符串
TypedArray可以直接獲得引用的值
// 系統(tǒng)對于包名為com.tencent.qq com.tencent.mm 的會不殺死熔任??所以可以偽裝成qq的包名
// 之后系統(tǒng)就排除了仙蛉,不會殺死笋敞??荠瘪?
// 夯巷。最后zygote進程進入監(jiān)聽狀態(tài)。一旦Android上層有創(chuàng)建新APK進程的需求哀墓,
// zygote進程便會為其分裂出新的進程趁餐。這個APK新進程,一開始便擁有了ART虛擬機
// 和zygote預(yù)先加載的各種系統(tǒng)類和資源篮绰,
// 能大大加速apk應(yīng)用的啟動后雷,同時也能節(jié)省很大的內(nèi)存開支。
Xposed Hook 會把method緩存到hashMap里面,所以可以讀取hashMap里面是否包含阿里的關(guān)鍵字段臀突,
例如:com.alibaba,com.taobao
// 因為有可能用戶喜歡裝xposed勉抓,所以不能因為發(fā)現(xiàn)了xposed就提示不安全
// 觀察者模式實則是 觀察屬性的實現(xiàn),對感興趣的屬性注冊候学,
// 例如 view 有多種屬性藕筋,onClick,onTouch梳码,onCreate隐圾,ondestory
// 所以可以對特定的屬性感興趣,setNotifyEvent("onClick",void(func));
public void onClick(){
/**
*/
for(int i=0;i<observers.size();i++){
observers.get(i).notify();
}
}
RxJava 有四個基本概念:Observable (可觀察者掰茶,即被觀察者)暇藏、 Observer (觀察者)、
subscribe (訂閱)濒蒋、事件盐碱。Observable 和 Observer 通過 subscribe() 方法實現(xiàn)訂閱關(guān)系
,從而 Observable 可以在需要的時候發(fā)出事件來通知 Observer啊胶。
just(T...): 將傳入的參數(shù)依次發(fā)送出來甸各。
from(T[]) / from(Iterable<? extends T>) : 將傳入的數(shù)組或 Iterable 拆分成具體對象后,依次發(fā)送出來焰坪。
創(chuàng)建了 Observable 和 Observer 之后趣倾,再用 subscribe() 方法將它們聯(lián)結(jié)起來,
整條鏈子就可以工作了某饰。代碼形式很簡單
observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);
public Subscription subscribe(Subscriber subscriber) {
subscriber.onStart();
onSubscribe.call(subscriber);
return subscriber;
}
調(diào)用 Subscriber.onStart() 儒恋。這個方法在前面已經(jīng)介紹過宏悦,是一個可選的準(zhǔn)備方法伐弹。
調(diào)用 Observable 中的 OnSubscribe.call(Subscriber) 离陶。在這里控乾,事件發(fā)送的邏輯開始運行。從這也可以看出洼哎,在 RxJava 中边败, Observable 并不是在創(chuàng)建的時候就立即開始發(fā)送事件业扒,而是在它被訂閱的時候减途,即當(dāng) subscribe() 方法執(zhí)行的時候酣藻。
將傳入的 Subscriber 作為 Subscription 返回。這是為了方便 unsubscribe().
Action1<String> onNextAction = new Action1<String>() {
// onNext()
@Override
public void call(String s) {
Log.d(tag, s);
}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
// onError()
@Override
public void call(Throwable throwable) {
// Error handling
}
};
Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
Log.d(tag, "completed");
}
};
// 自動創(chuàng)建 Subscriber 鳍置,并使用 onNextAction 來定義 onNext()
observable.subscribe(onNextAction);
// 自動創(chuàng)建 Subscriber 辽剧,并使用 onNextAction 和 onErrorAction 來定義 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自動創(chuàng)建 Subscriber ,并使用 onNextAction税产、 onErrorAction 和 onCompletedAction 來定義 onNext()怕轿、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
Action0 是 RxJava 的一個接口偷崩,它只有一個方法 call(),這個方法是無參無返回值的撞羽;
由于 onCompleted() 方法也是無參無返回值的阐斜,因此 Action0 可以被當(dāng)成一個包裝對象,
將 onCompleted() 的內(nèi)容打包起來將自己作為一個參數(shù)傳入 subscribe() 以實現(xiàn)不完整定義的回調(diào)放吩。
這樣其實也可以看做將 onCompleted() 方法作為參數(shù)傳進了 subscribe()智听,相當(dāng)于
其他某些語言中的『閉包』。 Action1 也是一個接口渡紫,它同樣只有一個方法 call(T param),
這個方法也無返回值考赛,但有一個參數(shù)惕澎;與 Action0 同理,由于 onNext(T obj) 和
onError(Throwable error) 也是單參數(shù)無返回值的颜骤,因此 Action1 可以將 onNext(obj)
和 onError(error) 打包起來傳入 subscribe() 以實現(xiàn)不完整定義的回調(diào)唧喉。事實上,雖然
Action0 和 Action1 在 API 中使用最廣泛忍抽,但 RxJava 是提供了多個 ActionX 形式的接
口 (例如 Action2, Action3) 的八孝,它們可以被用以包裝不同的無返回值的方法。
排序 :onNext,onError,onCompleted
Scheduler (調(diào)度器)鸠项。
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});
由于 subscribeOn(Schedulers.io()) 的指定干跛,被創(chuàng)建的事件的內(nèi)容 1、2祟绊、3楼入、4 將會在 IO
線程發(fā)出;而由于 observeOn(AndroidScheculers.mainThread()) 的指定牧抽,因此
subscriber 數(shù)字的打印將發(fā)生在主線程 嘉熊。事實上,這種在 subscribe() 之前寫上兩句
subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式
非常常見扬舒,它適用于多數(shù)的 『后臺線程取數(shù)據(jù)阐肤,主線程顯示』的程序策略。
.subscribeOn(Schedulers.io()) 指定subscribe()的創(chuàng)建在io線程
http://gank.io/post/560e15be2dca930e00da1083讲坎,
// 模糊md5 取md5孕惜,只取文件部分的進行md5計算
本地廣播優(yōu)點:
發(fā)送的廣播只會在自己App內(nèi)傳播,不會泄露給其他App衣赶,確保隱私數(shù)據(jù)不會泄露
其他App也無法向你的App發(fā)送該廣播诊赊,不用擔(dān)心其他App會來搞破壞
比系統(tǒng)全局廣播更加高效
http連接一般有個md5檢驗,所以可以直接hook一下MessageDigest類府瞄,打印出該md5
https://bbs.aliyun.com/read/275662.html // 更改阿里的顏色設(shè)置為32色
Microsoft Windows 7 (32 or 64bits)
Microsoft Windows 8 (32 or 64bits)
Microsoft Windows 10 (32 or 64bits)
硬件環(huán)境要求:
CPU:至少雙核CPU(CPU支持VT-x或者AMD-V虛擬化能夠大大提升使用體驗碧磅,通過BIOS設(shè)置開啟)碘箍,支持Intel和Amd (支持所有amd cpu)
內(nèi)存:至少2G;
顯卡:完整的顯卡驅(qū)動程序已安裝鲸郊,支持OpenGL 2.0或以上
base64編碼前后不一致問題:
編碼要統(tǒng)一
因為base64 編碼是byte編碼丰榴,所以肯定不會出錯
出錯的是new String()
tmp = Base64.decode(data) 肯定是正確的,
但是 new String(tmp) 可能出錯秆撮,tmp可能是gbk編碼的
一個小時大概能跑6000條
fastJson // GSON
jsonObject 不支持序列化 所以Intent跳轉(zhuǎn)的時候四濒,可以把jsonObject設(shè)置為一個static object保存,
之后在新的activity里面再把static object取出
UncaughtException處理類职辨,當(dāng)程序發(fā)生UnCaught異常的時候盗蟆,由該類來接管程序,并記錄發(fā)送錯誤報告
需要在Application中注冊舒裤,為了要在程序啟動時候就監(jiān)控整個程序
handleException方法:
1.發(fā)送錯誤日志到服務(wù)器
2.給用戶崩潰前的友好提示
3.把錯誤代碼記錄到sd卡
騰訊的Bugly平臺喳资,異常分析平臺,告訴你某個類怎么修復(fù)腾供。
服務(wù)器 自動打包
splash廣告--->引導(dǎo)頁--->首頁
TCP+ protobuf
Monkey是Android系統(tǒng)固件自帶的性能測試工具,他可以模擬各種按鍵仆邓、觸屏、軌跡球伴鳖、activity等事件节值。