sleepasandroid
㈠ 安卓 13側載 App 許可權將被進一步限制
安卓 13側載 App 許可權將被進一步限制
安卓 13側載 App 許可權將被進一步限制,Android 13 Beta 1 更新,到了下半年,我們就能陸續看到第一批更新 Android 13 系統的設備了。安卓 13側載 App 許可權將被進一步限制。
安卓 13側載 App 許可權將被進一步限制1
據 Android Police 報道,Android 的無障礙服務旨在為殘障用戶提供幫助,但這套工具非常強大,以至於其他應用程序經常使用它來啟用引人注目的功能。不幸的是,無障礙服務通常也是惡意軟體的門戶,以此來控制電話或獲取個人數據。在 Android 13 中,谷歌正在進一步打擊對無障礙服務的訪問,使側載應用更難獲得訪問許可權。
Android 13 對側載 App 引入了新的限制,阻止用戶授予他們使用無障礙服務的權利。鑒於許多網路釣魚和惡意軟體攻擊是通過誘騙用戶從應用商店外部安裝 APK 來進行的,這可能會使不良行為者更難劫持毫無戒心的用戶手機。
不過,谷歌並沒有完全阻止側載應用程序使用無障礙服務。一旦進入對話框,說明相關應用程序的輔助功能服務受到限制,你可以通過「允許受限設置」菜單條目在右上角的應用程序信息屏幕下激活訪問許可權,因此,如果你是有興趣使用合法應用程序增強手機的高級用戶,仍然可以這樣做。
這似乎是一個漏洞,惡意應用程序可以通過指示用戶啟用受限設置來規避。因此,谷歌仍有可能在穩定的 Android 13 上線之前改變這種行為。
新規則對用戶在 Play 商店中也有的應用程序有影響。當我們從 APK Mirror 側載舊版本的 Sleep as Android 時,它使用輔助功能服務來防止在嘗試關閉鬧鍾時關閉手機,無法啟用輔助功能服務,即使將其更新到通過 Play 商店提供的最新版本。
雖然用戶仍然可以使用前面描述的解決方法訪問 Android 13 Beta 1 中的輔助功能服務,但對於那些在 Play 商店推出之前將應用程序側載到最新狀態的用戶來說,這是一個額外的步驟。
還需要注意的是,谷歌只限制側載應用程序。如果你使用 F-Droid 或亞馬遜應用商店等替代應用分發平台,將不會遇到無障礙服務限制,谷歌可能會認為應用商店中的應用至少在一定程度上是經過篩選的。
同時,默認情況下,在 Google Play 商店中分發的應用程序根本無法使用無障礙服務,除非它們是專門為無障礙而創建的。當其他應用程序開發人員可以通過漫長的過程向谷歌證明他們的應用通過無障礙服務得到了極大的增強時,他們仍然可以要求豁免,但一般來說,谷歌強烈反對使用無障礙服務。
事實上,通話記錄應用程序是最新感受到這些限制的應用程序,谷歌不再允許它們使用無障礙服務來記錄電話通話。
安卓 13側載 App 許可權將被進一步限制2
到了下半年,我們就能陸續看到第一批更新 Android 13 系統的設備了。
距離去年 Android 12 Beta 版發布已經過去接近一年,無論此刻你的手機是否已經收到基於 Android 12 而來的更新推送,Android 13 的更新都已經進入了最新的 Beta 測試階段,從早先公布的 Android 更新時間線來看,距離進入各種系統功能都趨於穩定的階段也僅一步之遙。
雖然近兩年 Android Beta 測試計劃時間表都有較多的提前,但隨著時間進入五月,新一年的 Google I/O 照例也即將於 5 月 11 日正式開幕,屆時也會公布所有 Android 13 中將會正式加入的重要功能。
但在那之前,我們仍然可以通過現有的 Android 13 Beta 1 更新,先來大致了解到 Android 13 中有哪些值得期待的好料。
應用獨立語言設置
這個功能對於 iOS 用戶來講肯定不會陌生,但 Android 卻是一直到第十三個大版本更新才終於等來。這一功能能讓應用獨立於系統所設置的語言之外設置另一種顯示語言(當然前提仍需要應用本身提供了多語言的支持),這個功能往往會在使用一些語言類應用時相當方便。
在 Android 13 中,在系統設置中的「語言&輸入」菜單打開之後,就可以看到新的獨立應用語言設置選項。
雖然在最新的 Android 13 Beta 1 中,這個設置選項被暫時隱藏了起來,但預計出現在最終的 Android 13 正式版更新中並不會有太多的問題。
系統主題更進一步
Android 12 之所以被很多人認為是自 Android 5.0 以來改進最大的一次更新,很大程度上要歸功於 Google 新引入的 Material You 主題取色系統。簡而言之,就是一套可以跟隨手機的桌面壁紙更換,來一次性自動更換手機的主題色、圖標、桌面小組件,乃至第三方應用內頁面設計都能一同被重新載入。
但也正是由於 Android 12 中在主題系統部分大刀闊斧地改進太多,甚至 Android 官方承諾的一些實現效果,最終都未能在 Android 12 正式版中出現,因此也有了「Android 12 分兩年更新完」的說法。
事實也確實如此,在 Material You 主題應用實現的部分,一些 Android 12 中已經「PPT 首發」的內容,直到最近的 Android 13 Beta 1 才算是得到了最終的更新:例如下面的 Android 13 媒體卡片新增動畫效果。
Material You 取色效果給了更多選擇:在 Android 13 Beta 1 中,取色選擇從 Android 12 時期的四個選擇,直接升級為了壁紙提取顏色 + 基本顏色共計 32 種顏色組合,兩種不同的取色演算法能從壁紙顏色中分別能生成單色、雙色以及三色的可選組合。讓主題樣式也有了更多可選項。
Material You 圖標取色同樣是重要的組成部分之一:在開啟主題圖標選項之後,桌面上適配過的應用圖標也都可以跟隨手機主題色設置來改變樣式,但在 Android 12 階段,這一功能的適配進度比較緩慢,過去一年之後也仍只有少數第三方 App 針對這一功能進行了適配。
為了解決這一問題,在 Android 13 中引入了新的主題圖標 API,應用開發者只需在開發 App 時提供一個單色的應用圖標,就能在 Android 13 中應用到動態圖標樣式功能,大幅降低了開發者適配新功能的開發成本。另外 Google 也已經在與其他 Android 手機廠商合作,將這一功能推向更多 Android 第三方操作系統上。
隱私安全仍是重點
隱私許可權控制同樣是 Android 12 就已經重點關注的改進方向之一,而且在這一點上原生 Android 直接對系統底層的改動對於其他第三方 Android 系統來講同樣有著重要的啟示意義。例如在 Android 12 中首次出現了可以一鍵全局禁用攝像頭/麥克風的控制中心卡片設計。
關掉這些開關之後,禁用攝像頭甚至無法使用 Pixel 手機自帶的人臉解鎖,而禁用麥克風許可權則無法通話;而在 Android 13 中,這些針對系統許可權的控制收緊的趨勢也有更多進一步改進,全局許可權選項中還新增了新的地理位置一項,並將相機/麥克風許可權一並整合成新的「隱私控制」卡片。
在設置中,Android 13 還將過去散落在各處的隱私相關設置進一步整合,成了新的「隱私信息中心」,供用戶直接檢查最多過去一周各項許可權的使用情況,包括系統應用在內的許可權使用都可以在這里看到詳細到分鍾的許可權使用記錄。
Android 13 中還引入了獨立的照片選擇器概念:比如你想在某「小而美」的聊天軟體中給朋友分享一組照片,但卻又不想授予軟體訪問你手機中所有照片的許可權,這時 Android 13 新加入的照片選擇器就可以手動選出你需要分享的照片內容,並僅將你所選中的照片的訪問許可權授予聊天應用,最大限度降低隱私泄露的風險。
大屏幕體驗& 智能家居
在 Android 12 更新發布之後,Android 緊隨其後啟動了另一個特殊的系統測試計劃 —— Android 12L;這一目的在於優化大屏幕/折疊屏的更新被賦予了獨立系統代號,甚至在很大程度上成為了一個與早期 Android 13 測試計劃並行的開發項目。
在 Android 13 中,針對折疊屏不同場景使用/不同屏幕尺寸的顯示模式加入了更多深層的改進,一邊在多屏幕切換之間獲得更好的顯示效果;例如屏幕 90 度展開狀態的'「桌面模式」。
目前 Android 13 中,面向宅家場景中需求經常被提到的智能家居也是新功能加入的重要方向之一,例如 Android 13 Beta 1 中已經加入「鎖屏控制智能設備」的選項,這一更新允許適配過的智能家居服務(例如米家、Google Home 等),無需解鎖手機,在鎖屏狀態下即可進行基礎的智能家居操作。
從目前現有信息來看,Android 13 中還將加入一個「媒體點擊轉移」(Media Tap to Transfer)的功能;雖然目前這一功能實際信息相對於其他已經出現的功能來講還很少,但這會是一個類似蘋果 AirDrop、華為分享功能的 Android 原生媒體投射功能,但檢測到同一區域網下有平板/筆電等設備正在使用中,或是使用 UWB 近場通信,靠近智能音箱即可將音樂投射到上面播放。
同樣屬於尚未發布,但已經在相關代碼中已經有所提到的,還有 Android 13 中新增的「Hub 模式」可以讓多個用戶在同一台 Android 13 設備之上共用一套數據,同時還能保留多個用戶之間的個人信息。
這一功能明顯並非是為了個人使用的平板電腦而准備,但三星也曾在今年的 CES 期間展示過搭載 Android 系統的「智能家居中樞」:本質上其實是一款 Android 系統平板,但除了搭配充電底座之外,也加入了更多針對家居使用場景的軟體改進。
這也側面印證了此前關於 Google 會發布搭載 Android 系統的智能顯示屏的傳聞,當然這些未必會是與 Android 13 一同出現在五月即將到來的 Google I/O 大會中的內容。但仍然值得期待。
安卓 13側載 App 許可權將被進一步限制3
谷歌將在下個月舉行年度開發者大會,屆時可能會對Android 13的更新內容做全面的介紹。至於正式版,預計要等到下半年或更晚的時候了。
據了解,Android 13首個Beta版本最主要的新功能,是此前已經出現在Android 13最初兩個開發者預覽版中就出現的,其中有藍牙低能量音頻,以及新的文件訪問許可權,用戶可以決定應用能夠讀取相冊中的哪些文件。此外,還有一個全新的許可權,能夠有效過濾垃圾郵件的通知,但認為這一功能在國內用處不大。
Android 13在界面設計風格上和Android 12沒有太大區別,但在細節方面做了部分改進,比如音樂通知欄中的進度條,改為動態波浪樣式。此外,新版還支持用戶編輯剪貼板中的內容,對於常用復制粘貼的人會比較方便,建議國內深度定製系統也學習一下。
此前爆料的MGLRU多頁面回收策略,Android 13首個測試版本似乎也沒有實裝,可能得等到正式版,用戶才能體驗到「滿血」的原生系統。總體來看安卓13更像是12的隱私許可權加強版,現在的操作系統都在許可權做功課,功能、設計方面已經沒有特別明顯的改進,開始像iOS那樣「擠牙膏」了。
在國內,隨著近幾年手機廠商對操作系統愈發重視,基於安卓的深度定製系統已經十分完善,從易用性、人性化的角度來看,已經能夠迎合絕大部分消費者的需求,就連iOS、谷歌原生的某些新功能都是從國內定製系統中借鑒的。個人隱私方面,MIUI、ColorOS、Magic UI、Origin OS等定製系統也做到了,做的甚至還不差。
認為,近幾年大家對系統大版本更新的期待值已經遠不如以前,一方面是升級點有限,另一方面則是深度定製系統的崛起,原生系統或許就只剩下大版本更新快,動效流暢而已了。在用國產手機的小夥伴也不用著急,基於Android 13定製的正式版系統估計明年才會陸續推送。
㈡ 為什麼 12G 內存的 Android 手機依舊會被殺後台
不知不覺間 Android 陷入了一個關於「後台」的怪圈:一邊各大廠商陸續推出了 12G RAM 的手機,另一邊你剛剛放到後台的下載任務沒有如預期那樣後台掛機下載,打開微信發現還得陪啟動畫面的孤獨小人共賞藍色星球、按照教程辛辛苦苦做了半個小時的 Tasker 規則、卻沒有按照計劃自動執行……
於是一個耳熟能詳的句子開始在我們腦海中成型—— 我的後台又被「殺」了 。
應用開發者的「控訴」
遇到上述問題的人不止你一個,很多人選擇向這些應用的開發者反饋問題,殊不知問題其實不在應用本身。
Android 平台著名睡眠追蹤應用 Sleep as Android 的開發團隊 Urbandroid Team 不堪其擾,索性上線了一個名為「別『殺』我應用」的網站,矛頭直指手機廠商糟糕的後台管理機制。
以三星為例,Urbandroid Team 稱,三星的部分機型在升級到基於 Android 9 的 One UI 後「殺後台」現象變得尤為嚴重,自適應電池(Adaptive Battery)機制相比原生 Android 變得尤為激進,3 天內沒有啟動過的應用甚至無法從後台再次啟動。最為糟糕的情況是,如果你安裝了一個可以自動跳過周末的第三方鬧鍾,那這個鬧鍾應用很有可能不會像系統鬧鍾那樣在下周一早上准時響起……
正如「別『殺』我應用」網站上控訴的那樣,擁有類似機制的還包括華為、一加、小米、華碩等等手機廠商的定製版 Android 系統,它們管理後台的方式大同小異,但都秉承著 iOS 上那一套「劃掉就殺掉」的原則——當我們把某款應用的任務卡片從多任務界面劃去,它們也就徹底從手機後台中抹除掉了。
這里你可能會問很多問題:
我們得從一些基礎的原理說起。
Android 的內存回收機制
在 官方文檔 中,Google 將「不受應用自身直接控制的應用進程生命周期」描述為 Android 最為基礎也最為獨特的核心特性,這里我們不妨將「應用進程生命周期」暫時理解為文章開頭和第一部分所說的「後台」或「後台進程(process)」。
所以 Android 應用的後台進程去留本應是由 Android 系統來決定的 。
當可用運行內存空間不足時,Android 系統會自行決定對特定應用後台進程佔用的空間進行回收釋放,這個過程中 Android 揮舞著的那把大刀,叫做 LMK(Low Memory Killer)。那 LMK 又是如何判斷哪些應用可以被「殺」掉、哪些應用又該暫時放過的呢?
每個應用都有各種各樣的組成部分,其中特定組件的運行狀態共同組成了一套供 LMK 進行內存回收的「優先順序」參考,包括:前台進程、可見進程、服務進程和緩存進程。
前台進程、可見進程和服務進程往往與我們正在手機上執行的操作直接或間接相關 ,比如正在前台供我們交互和操作的活動窗口(Activity)、正在通過廣播接收器(BroadcastReceiver)等待觸發的 Tasker 規則、正在後台通過 Wi-Fi 網路自動上傳備份照片的 Google Photos 以及前面提到的有待觸發的鬧鍾等等。這些進程優先順序從高到低依次遞減,LMK 一般不會觸及。
緩存進程則是那些暫時放在運行內存中的部分,也是和本文探討話題主要相關的重點 。
只有在極端情況下 ,比如 Android 系統在回收掉所有緩存進程後發現空閑內存依然不夠用(比如在低內存的「老爺機」上運行《崩壞 3》),這時 LMK 才會根據優先順序繼續對服務進程、可見進程和前台進程採取回收策略。 而當這些我們在正常使用中能夠直觀感受到的進程都不得不被被回收時 ,文章開頭提到的微信重載、音樂中斷、下載消失等等現象也就出現了。
誰動了你的後台
在可用內存充裕的情況下遭遇「殺後台」現象,一方面可能是 LMK 這把「大刀」出了問題(常見於 Android 9 時期的 Pixel 3 用戶),另一方面則有可能是其它規則額外干預了 Android 系統正常的內存回收機制。
這里提到的「其它規則」主要有兩種形式,一種類似部分華為設備上預裝的「省電精靈」,它會將所有沒有加入後台白名單中的應用後台統統清除,另一種則依託於 Google 推出的 後台檢查 、 後台限制 和 自適應電池 等功能進行「魔改」,讓這些功能的實際效果遠超預期,甚至達到意料之外的負面效果。
根據 Don't kill my app! 的統計,第二種後台干預機制在三星、一加和早期的諾基亞機型中常見,這里廠商們通常會用到一種類似「白名單」的方法來進行過濾。
以三星手機基於 Android 9 的 One UI 為例,除了微信、QQ 等國內常見應用,One UI 默認會為所有第三方應用關閉「允許後台活動」這一選項,同時開啟「優化電池使用量」這一功能。
部分搭載氫 OS 的一加機型則將上面提到的應用進程進行拆分,除了基於原生 Android 的後台限制、電池優化,還有一套名為「自啟動管理」的設置來對應用的自啟動進行管理以及一套名為「深度優化」的電池優化機制,後者會造成很多智能手錶、手環設備在一段時間後丟失與手機的藍牙連接,最終導致睡眠追蹤、運動記錄等等功能的失效。
問題在於上述功能埋藏較深,一般用戶在安裝應用後往往不會第一時間前往設置,一加的氫 OS 更是以系統更新之後自動重置部分用戶設置聞名,那些需要在後台正常工作的應用,因此也被都被直接扔進了原生 Android 中用來限制「毒瘤」應用的「黑箱」里。
換句話說,國內大部分定製 ROM 在後台管理這件事情上都選擇採用一種「 寧肯錯殺一千不肯放過一個 」的做法。
關聯閱讀: 控制頻繁啟動的「毒瘤」,Android 9.0 用這些方法讓你的手機更省電
多任務管理還是後台管理?
從某種程度上來說,國產手機廠商在 Android 後台管理上的做法雖然偏激,但它們都是國內特殊生態下的產物 。
一方面,盡管 Google 為 Android 設想了一套非常理想化的應用運行與後台管理機制 ,但大多數於原生 Android 中行之有效的後台管理機制在國內似乎都會變成「雞肋」。
如果 Google 有 100 種提升 Android 應用運行效率,保證後台綠色、純凈的方法,國內毒瘤應用開發商就有 101 種繞過這些限制的方法。
藉助共用的第三方推送服務實現鏈式喚醒、藉助透明的懸浮窗保證後台存活、通過不斷獲取定位的方式來避免進程被系統回收……不管是出於實現消息推送這樣單純的目的還是為了不斷喚醒用戶設備以實現 KPI 目標這種下作的行為,在國內 Android 生態中均有出現。
雖然國內外的具體環境有所不同,但這類設計不規范的 Android 應用帶來的問題卻是一樣的,這類應用放在後台不僅不會為我們帶來便利,反而還會因為頻繁喚醒設備帶來不小的耗電問題。待機續航問題作為懸在國產 Android 機頭頂的幾把利劍之一,手機廠商不得不各自從系統層面推出自家的應對機制——這就有了上面提到的各種偏激式的後台管理方法。
另一方面,這里還涉及到一個非常重要的概念區分 :多任務管理和後台管理究竟是不是一回事?
國內 Android 生態由於早期受 iOS 影響較深,無論是開發商還是用戶都更傾向於把「將應用卡片從多任務列表裡劃掉」的行為理解為清除對應用的後台進程。在上面提到的特殊生態環境的影響之下,這里被清除的後台進程往往又包括那些用於保證應用後台運行的可見進程、服務進程乃至前台進程在內。
在酷安應用市場,甚至還有得以在原生 Android 上實現類似「劃掉卡片即停止運行」效果的應用,iOS 的後台管理理念在國內有多麼深入人心可見一斑。
但這種後台管理理念卻與 Google 對 Android 的多任務管理設計方式相悖。Google 一直以來都將 Android 手機上呼出任務卡片的那個界面叫做 Recents,最近幾個版本的 Android 系統更是將其本地化為「概覽」。結合 Google 在 Android 9 和 Android 10 手勢交互上的變革,注重多任務管理而非後台管理的意圖也越發明顯。
當最近運行的應用以一張張卡片的形式呈現在我們面前時,Google 想要呈現的是一個能夠讓我們在不同任務間快速切換的多任務交互,而在理想狀態下,後台管理則是交由系統處理、完全不應被用戶感知的。
至於如何理性看待 Android 平台的後台管理,這里我們不妨借用綠色守護開發者 @OasisFeng 在「Android 多任務界面的劃除交互」這個話題上的 答疑 來回答這個問題:
換句話說, 今後絕大部分需要在海外市場搭載 Google 服務上市的手機都必須滿足這個要求 。
小結
就在上周三(9 月 25 日),醞釀已久的安卓統一推送聯盟正式宣布收到華為、OPPO、一加和 realme 四家公司的進度確認,雖然 Google 的缺席也讓國內 Android 生態也變得異常復雜,但國內 Android 設備也能用上的統一推送服務也算是終於邁出了具有實際意義的第一步。
只是距離轉變人們對 Android「殺後台」這件事的看法依然還有很長的路要走。事實上,國內早在四五年前就出現過一次對「Android 需不需要『殺後台』」問題的科普,但收效甚微,盲從 iOS 設計風格和交互邏輯國內 Android 廠商要負很大一部分責任。
希望靠譜、省電的統一推送系統能成為改觀的第一步,也希望 @OasisFeng 口中那個甚至可以跨越設備重啟恢復「後台狀態」的理想化生態早日到來——至於當下,我們依然只能見招拆招,遇到應用無法正常執行後台任務時打開手機設置仔細翻找、設置,把它們扔進白名單或是給它們的後台卡片套個「鎖」……
下載、安裝了一款非白名單應用,該如何確保它不被「殺後台」呢?歡迎在評論區把你的設置方法分享給大家。
㈢ android自帶時鍾應用的這個效果是怎麼做的
次的小程序是一個Android小時鍾。主要用到知識有Handler,Thread,Canvas,Path.
Handler:主要是用來接收子線程發送的數據,並用此數據配合主線程更新UI。Handler運行在主線程,通過message來與子線程傳遞數據。我只用到了sendMessage(Message)方法。
Thread在java中剛學過了,所以用起來還是比較簡單的,就不多說了。
Canvas類就是表示一塊畫布,你可以在上面畫你想畫的東西。當然,你還可以設置畫布的屬性,如畫布的顏色/尺寸等。
這東西我是第一次用,所以查了下canvas提供的方法。在時鍾小程序中,我主要用的是rotate(),旋轉畫布。
Path也是第一次用到。moveTo和lineTo是用來設置開始的基點和最後的基點。我用path來畫時鍾的分針、秒針和時針。
關於android畫圖方面的知識是第一次接觸到,(其實本來是想從網上下載一個時鍾表盤的圖片直接拿來用的),但是由於找不到合適的指針的圖片,所以還是用畫的了,雖然這樣就會顯得很樸素了,但是基本功能還是實現了。截圖如下:
importjava.util.Calendar;
importandroid.annotation.SuppressLint;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.Color;
importandroid.graphics.Paint;
importandroid.graphics.Path;
importandroid.view.View;
@SuppressLint({"ResourceAsColor","DrawAllocation"})
publicclassdrawextendsView{
publicdraw(Contextcontext){
super(context);
}
publicvoidonDraw(Canvascanvas){
Paintpaint=newPaint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);//空心的畫筆
paint.setStrokeWidth(3);//設置paint的外框寬度
drawDial(canvas,paint);//繪製表盤
drawHand(canvas,paint);//繪制時針、分針、秒針
}
publicvoiddrawHand(Canvascanvas,Paintpaint){
intx=310;
inty=x;
inthour;
intminute;
intsecond;
finalCalendarcalendar=Calendar.getInstance();
hour=calendar.get(Calendar.HOUR);
minute=calendar.get(Calendar.MINUTE);
second=calendar.get(Calendar.SECOND);
floath=((hour+(float)minute/60)/12)*360;
floatm=((minute+(float)second/60)/60)*360;
floats=((float)second/60)*360;
//時針
paint.setColor(Color.WHITE);
canvas.save();//線鎖定畫布
canvas.rotate(h,x/2,y/2);//旋轉畫布
Pathpath1=newPath();
path1.moveTo(x/2,y/2);//開始的基點
path1.lineTo(x/2,y/4);//最後的基點
canvas.drawPath(path1,paint);
canvas.restore();
//分針
paint.setColor(R.color.MediumSlateBlue);
canvas.save();
canvas.rotate(m,x/2,y/2);//旋轉畫布
Pathpath2=newPath();
path2.moveTo(x/2,y/2);//開始的基點
path2.lineTo(x/2,y/6);//最後的基點
canvas.drawPath(path2,paint);
canvas.restore();
//秒針
paint.setColor(Color.BLUE);
canvas.save();
canvas.rotate(s,x/2,y/2);//旋轉畫布
Pathpath3=newPath();
path3.moveTo(x/2,y/2);//開始的基點
path3.lineTo(x/2,y/9);//最後的基點
canvas.drawPath(path3,paint);
canvas.restore();
}
publicvoiddrawDial(Canvascanvas,Paintpaint){
intx=310;
inty=x;
paint.setColor(Color.WHITE);
canvas.drawCircle(x/2,y/2,x/2-2,paint);
canvas.drawCircle(x/2,y/2,x/40,paint);
Pathpath9=newPath();//接下來的是,畫時針的刻度
path9.moveTo(2,y/2);
path9.lineTo(y/18,y/2);
canvas.drawPath(path9,paint);
Pathpath12=newPath();
path12.moveTo(x/2,2);
path12.lineTo(x/2,y/18);
canvas.drawPath(path12,paint);
Pathpath3=newPath();
path3.moveTo(x-2,y/2);
path3.lineTo(x-x/18,y/2);
canvas.drawPath(path3,paint);
Pathpath6=newPath();
path6.moveTo(x/2,y-2);
path6.lineTo(x/2,y-y/18);
canvas.drawPath(path6,paint);
canvas.save();
canvas.rotate(32,x/2,y/2);
Pathpath10=newPath();
path10.moveTo(2,y/2);
path10.lineTo(x/32,y/2);
canvas.drawPath(path10,paint);
Pathpath1=newPath();
path1.moveTo(x/2,2);
path1.lineTo(x/2,y/32);
canvas.drawPath(path1,paint);
Pathpath4=newPath();
path4.moveTo(x-1,y/2);
path4.lineTo(x-x/32,y/2);
canvas.drawPath(path4,paint);
Pathpath7=newPath();
path7.moveTo(x/2,y-2);
path7.lineTo(x/2,y-y/32);
canvas.drawPath(path7,paint);
canvas.restore();
canvas.save();
canvas.rotate(60,x/2,y/2);
Pathpath11=newPath();
path11.moveTo(2,y/2);
path11.lineTo(x/32,y/2);
canvas.drawPath(path11,paint);
Pathpath2=newPath();
path2.moveTo(x/2,2);
path2.lineTo(x/2,y/32);
canvas.drawPath(path2,paint);
Pathpath5=newPath();
path5.moveTo(x-2,y/2);
path5.lineTo(x-x/32,y/2);
canvas.drawPath(path5,paint);
Pathpath8=newPath();
path8.moveTo(x/2,y-2);
path8.lineTo(x/2,y-y/32);
canvas.drawPath(path8,paint);
canvas.restore();
}
}
㈣ Android studio 開發app,如何抵抗動態調試,反調試代碼怎麼寫請寫上詳細代碼。
為了保護關鍵代碼被逆向分析,一般放在應用程序初始化過程中,如init_array,或jni_onload函數里進行檢查代碼執行。
1.調試檢測
對調試器的檢測(ida,gdb,strace, ltrace等調試工具)
a.父進程檢測
b.當前運行進程檢測
例如對android_server進程檢測。針對這種檢測只需將android_server改名就可繞過
[objc] view plain
pid_t GetPidByName(const charchar *as_name) {
DIR *pdir = NULL;
struct dirent *pde = NULL;
FILEFILE *pf = NULL;
char buff[128];
pid_t pid;
char szName[128];
// 遍歷/proc目錄下所有pid目錄
pdir = opendir("/proc");
if (!pdir) {
perror("open /proc fail.\n");
return -1;
}
while ((pde = readdir(pdir))) {
if ((pde->d_name[0] < '0') || (pde->d_name[0] > '9')) {
continue;
}
sprintf(buff, "/proc/%s/status", pde->d_name);
pf = fopen(buff, "r");
if (pf) {
fgets(buff, sizeof(buff), pf);
fclose(pf);
sscanf(buff, "%*s %s", szName);
pid = atoi(pde->d_name);
if (strcmp(szName, as_name) == 0) {
closedir(pdir);
return pid;
}
}
}
closedir(pdir);
return 0;
}
c.讀取進程狀態(/proc/pid/status)
State屬性值T 表示調試狀態,TracerPid 屬性值正在調試此進程的pid,在非調試情況下State為S或R, TracerPid等於0
d.讀取 /proc/%d/wchan
下圖中第一個紅色框值為非調試狀態值,第二個紅色框值為調試狀態:
[objc] view plain
static void get_process_status(pid_t pid,const char* info,charchar *outline)
{
FILEFILE *fp;
char filename;
char line = {0};
snprintf( filename, sizeof(filename), "/proc/%d/status", pid );
fp = fopen( filename, "r" );
if ( fp != NULL )
{
while ( fgets( line, sizeof(line), fp ) )
{
if ( strstr( line, info ) )
strcpy(outline,line);
}
fclose( fp ) ;
}
return ;
}
static int getProcessStatus(int pid)
{
char readline = {0};
int result = STATUS_ELSE;
get_process_status(pid,"State",readline);
if(strstr(readline,"R"))
result = STATUS_RUNNING;
else if(strstr(readline,"S"))
result = STATUS_SLEEPING;
else if(strstr(readline,"T"))
result = STATUS_TRACING;
return result;
}
static int getTracerPid(int pid)
{
char readline = {0};
int result = INVALID_PID;
get_process_status(pid,"TracerPid",readline);
charchar *pidnum = strstr(readline,":");
result = atoi(pidnum + 1);
return result;
}
static int getWchanStatus(int pid)
{
FILEFILE *fp= NULL;
char filename;
char wchaninfo = {0};
int result = WCHAN_ELSE;
char cmd = {0};
sprintf(cmd,"cat /proc/%d/wchan",pid);
LOGANTI("cmd= %s",cmd);
FILEFILE *ptr; if((ptr=popen(cmd, "r")) != NULL)
{
if(fgets(wchaninfo, 128, ptr) != NULL)
{
LOGANTI("wchaninfo= %s",wchaninfo);
}
}
if(strncasecmp(wchaninfo,"sys_epoll\0",strlen("sys_epoll\0")) == 0)
result = WCHAN_RUNNING;
else if(strncasecmp(wchaninfo,"ptrace_stop\0",strlen("ptrace_stop\0")) == 0)
result = WCHAN_TRACING;
return result;
}
e. ptrace 自身或者fork子進程相互ptrace
[objc] view plain
ptrace me
if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
printf("DEBUGGING... Bye\n");
return 1;
}
void anti_ptrace(void)
{
pid_t child;
child = fork();
if (child)
wait(NULL);
else {
pid_t parent = getppid();
if (ptrace(PTRACE_ATTACH, parent, 0, 0) < 0)
while(1);
sleep(1);
ptrace(PTRACE_DETACH, parent, 0, 0);
exit(0);
}
}
f. 防止mp
利用Inotify機制,對/proc/pid/mem和/proc/pid/pagemap文件進行監視。inotify API提供了監視文件系統的事件機制,可用於監視個體文件,或者監控目錄。具體原理可參考:http://man7.org/linux/man- pages/man7/inotify.7.html
偽代碼:
[objc] view plain
void __fastcall anitInotify(int flag)
{
MemorPagemap = flag;
charchar *pagemap = "/proc/%d/pagemap";
charchar *mem = "/proc/%d/mem";
pagemap_addr = (charchar *)malloc(0x100u);
mem_addr = (charchar *)malloc(0x100u);
ret = sprintf(pagemap_addr, &pagemap, pid_);
ret = sprintf(mem_addr, &mem, pid_);
if ( !MemorPagemap )
{
ret = pthread_create(&th, 0, (voidvoid *(*)(voidvoid *)) inotity_func, mem_addr);
if ( ret >= 0 )
ret = pthread_detach(th);
}
if ( MemorPagemap == 1 )
{
ret = pthread_create(&newthread, 0, (voidvoid *(*)(voidvoid *)) inotity_func, pagemap_addr);
if(ret > 0)
ret = pthread_detach(th);
}
}
void __fastcall __noreturn inotity_func(const charchar *inotity_file)
{
const charchar *name; // r4@1
signed int fd; // r8@1
bool flag; // zf@3
bool ret; // nf@3
ssize_t length; // r10@3
ssize_t i; // r9@7
fd_set readfds; // @2
char event; // @1
name = inotity_file;
memset(buffer, 0, 0x400u);
fd = inotify_init();
inotify_add_watch(fd, name, 0xFFFu);
while ( 1 )
{
do
{
memset(&readfds, 0, 0x80u);
}
while ( select(fd + 1, &readfds, 0, 0, 0) <= 0 );
length = read(fd, event, 0x400u);
flag = length == 0;
ret = length < 0;
if ( length >= 0 )
{
if ( !ret && !flag )
{
i = 0;
do
{
inotity_kill((int)&event);
i += *(_DWORD *)&event + 16;
}
while ( length > i );
}
}
else
{
while ( *(_DWORD *)_errno() == 4 )
{
length = read(fd, buffer, 0x400u);
flag = length == 0;
ret = length < 0;
if ( length >= 0 )
}
}
}
}
g. 對read做hook
因為一般的內存mp都會調用到read函數,所以對read做內存hook,檢測read數據是否在自己需要保護的空間來阻止mp
h. 設置單步調試陷阱
[objc] view plain
int handler()
{
return bsd_signal(5, 0);
}
int set_SIGTRAP()
{
int result;
bsd_signal(5, (int)handler);
result = raise(5);
return result;
}