https://developer.android.com/guide/index.html
每個Android App都存活在獨立的安全沙箱內,具備下面4點特性:
Android操作系統是多用戶的linux操作系統,每個app都是一個獨立的user用戶;系統為每個app分配一個唯一的用戶ID,對應的app文件只有這個用戶ID的app才有訪問權限 ;每個App都運行在自己獨立的VM里,App間互相獨立;當需要執行App的組件時,才會啟動App進程,當任務結束或者系統內存回收時會停止進程;
安卓四大組件:Activity、Service、ContentPRovider、BroadcastReceiver。激活組件需要使用Intent這個異步消息,消息類型有兩種:顯式類型和隱式類型,顯式類型直接指定組件的類名,隱式類型通過action指定。
  注意:如果使用Intent啟動Service,要使用顯式類型的Intent,隱式類型的Intent有安全風險,無法確認哪個Service會響應這個Intent,并且用戶無法看到哪個Service啟動了,從Android 5.0(API21)開始,對于使用隱式Intent啟動Service的操作,系統會直接拋出異常,所以聲明Service的時候不要添加<intent-filter/>描述。
Android系統會運行在各種平臺之上,但不是所有的平臺都能提供應用要求的特性,所以需要在應用的manifest.xml中聲明App運行需要的條件,應用本身并不會讀取這些聲明,但是外部服務如Google Play會讀取這些聲明,從而過濾出能在當前設備環境運行的應用。
<manifest ... > <uses-feature android:name="android.hardware.camera.any" android:required="true" /> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> ...</manifest>設備兼容性包括:DeviceFeatures、PlatformVersion、ScreenConfiguration。
設備特性(Device Features):每個設備特性都有一個唯一的ID標識,比如磁羅盤傳感器的FEATURE_SENSOR_COMPASS、App小部件的FEATURE_APP_WIDGETS等,如果應用強依賴某一特性,那么可以禁止用戶安裝這個應用,或者降級處理。
用戶在 Google Play 應用商店搜索時,Google Play 會讀取這個應用的uses-feature聲明,從而過濾掉這個應用。
<manifest ... > <uses-feature android:name="android.hardware.sensor.compass" android:required="true" /> ...</manifest>在應用內降級處理
PackageManager pm = getPackageManager();if (!pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) { // This device does not have a compass, turn off the compass feature disableCompassFeature();}平臺版本(Platform Version):主要設置minSdkVersion和targetSdkVersion屬性
<manifest ... > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> ...</manifest>The minSdkVersion attribute declares the minimum version with which your app is compatible and the targetSdkVersion attribute declares the highest version on which you’ve optimized your app.
targetSdkVersion的定義表明應用需要后向兼容以前的Behaviors,新版本的系統要和之前的Behaviors習慣保持一致。,比如AlarmManager,從API19開始系統把Alarm的處理改為批量處理的策略,不再是之前每次時間一到就喚醒設備,以此提高電源效率。如果需要保持之前每次Alarm一到就喚醒設備的習慣,需要把targetSdkVersion設置為API18,這樣即使在新的系統上也能保持以前的處理習慣Behaviors。
屏幕配置(Screen Configuration):為了根據屏幕對設備進行分類,安卓定義了兩種設備特性:screen size (屏幕的物理尺寸)和screen density(屏幕上物理尺寸的密度DPI),系統會根據實際的設備尺寸自動選擇最合適的UI布局和圖片資源。
四種size:small, normal, large, xlarge
不同density:mdpi(medium), hdpi(hdpi), xhdpi(extra high), xxhdpi(extra-extra high), …
Android是一個權限隔離的系統,每個應用都是一個獨立的user,所以必須單獨申請權限,根據權限的敏感度,系統會自動賦予權限或者提示用戶授予權限。
應用需要的權限在manifest中聲明,普通權限系統會自動授予,敏感權限系統會提示用戶顯式授予:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.app.myapp" > <uses-permission android:name="android.permission.RECEIVE_SMS" /> ...</manifest>  系統獲取權限的方式由系統版本和targetSdkVersion決定:如果系統版本>=6.0(API23)并且targetSdkVersion>=23,應用是在運行時請求權限,而且用戶可以隨時撤銷權限,所以每次使用權限之前,應用都需要檢查是否有這個權限;其他情況下(系統版本<6.0||targetSdkVersion<23)系統是在安裝應用時請求授權,覆蓋安裝時如果添加了新權限,系統會再次請求用戶授權,一旦應用安裝完成,用戶只能通過卸載應用才能撤銷已授予的權限。執行沒有權限的操作,系統會把日志打印到System.log。
安卓系統還會進行權限調整,比如新版本對某個之前不需要授權的操作增加了權限,而舊版本的應用并沒有申請這個權限,為了保證應用能夠正常安裝運行,系統會根據targetSdkVersion自動增加這些權限申請。
所有的敏感權限都以權限組(Permission Groups)的方式管理,系統不會以某個具體權限的粒度提示用戶,而是以權限組的粒度申請授權,比如應用需要申請READ_CONTACTS權限,系統只會提示用戶該應用需要訪問設備通訊錄,用戶授權后,應用默認也獲取到了寫權限WRITE_CONTACTS。 屬于敏感權限組的權限見最后的表格。
  關于安卓應用簽名的機制可以讀一下這兩篇文章安卓簽名過程和安卓簽名驗證過程。
  簽名過程 的主要步驟:首先生成私鑰 -> 對apk中的所有Entry(文件)分別計算SHA1摘要+Base64編碼,寫入MANIFEST.MF文件 -> 對整個MANIFEST.MF文件計算SHA1摘要+Base64編碼,寫入CERT.SF文件頭部的SHA1-Digest-Manifest屬性 -> 再對MANIFEST.MF文件的每個屬性快分別計算SHA1摘要+Base64編碼,繼續寫入CERT.SF文件完成 -> 對CERT.SF文件使用私鑰計算簽名,將簽名和包含公鑰信息的數據證書一同寫入CERT.RSA保存完成。
簽名的安全性證明:如果Apk的任意一個文件被修改,MANIFEST.MF中的摘要將不再匹配,簽名驗證過程會報錯;如果修改文件后同步更新了MANIFEST.MF中的摘要信息,CERT.SF中的摘要還是不能匹配,簽名驗證過程還是會報錯;如果再同步更新了CERT.SF中的摘要,CERT.RAS中記錄數字簽名和新簽名還是不一致,而到這一步數字簽名因為沒有數字證書對應的私鑰,所以無法再偽造。所以APK的任意一個文件被修改后,必須要重新簽名,不然會提示安裝失敗。
簽名驗證過程 的主要步驟:直接對system_process進程打斷點跟蹤,驗證過程和簽名過程對應。安裝的主入口在PackageManagerServer.java#installPackageLI(),主要涉及的類包括:PackageManagerServer、PackageParser、StrictJarFile、JarVerifier;
# com.android.server.pm.PackageManagerServer.javaprivate void installPackageLI(InstallArgs args, PackageInstalledInfo res) { ... try { pp.collectCertificates(pkg, parseFlags); pp.collectManifestDigest(pkg); } catch (PackageParserException e) { res.setError("Failed collect during installPackageLI", e); return; } ...}簽名驗證的過程:主要是使用/META-INFO目錄下的簽名文件(.MF/.SF/.RSA),對當前Apk中各個文件的一致性進行校驗,而不是已安裝應用和新應用之間進行校驗,驗證的目的是防止應用被篡改。如果修改了應用并且重新簽名了,只要Apk簽名是正確的,應用還是能夠被正常安裝。
應用安裝的時候,Android系統會給安裝包分配一個單獨的Linux User ID,只要應用不卸載,這個ID就是固定不變的。一般來說出于安全的需要,每個應用都獨立分配一個UID,如果兩個App有著相同的簽名,系統才會分配相同的UID。應用創建的所有文件數據都會被這個應用的UID賦值標記,以防止被其他應用非法訪問。
自定義權限需要在Manifest中作事先聲明,需要注意的是系統不允許多個應用定義相同的權限名稱,除非應用使用了相同的證書簽名。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" > <permission android:name="com.example.myapp.permission.DEADLY_ACTIVITY" android:label="@string/permlab_deadlyActivity" android:descr 可以為四大組件定義訪問權限檢查:<activity android:permission=""/> 限制誰能啟動這個Activity( SecurityException)<service android:permission=""/> 限制誰能啟動或者綁定這個Service( SecurityException)<receiver android:permission=""/> 限制誰能發送廣播到這個BroadcastReceiver<provider android:permission="" android:readPermission="" android:writePermission=""/> 限制誰能訪問ContentProvider里的數據,讀寫分離  URI permissions:對于ContentProvider的訪問可以使用per-URI permissions進行更精細的權限控制,調用者啟動activity或者返回結果給caller時,可以在Intent中設置Intent.FLAG_GRANT_READ_URI_PERMISSION/Intent.FLAG_GRANT_WRITE_URI_PERMISSION,授權接收Activity訪問URI數據的權限,此時目標Activity不需要具有訪問ContentProvider的權限就可以訪問這個數據了。   
新聞熱點
疑難解答