התכונה "תפקידים באפליקציה" מאפשרת לאדמין ממחלקת IT להעניק הרשאות מיוחדות לאפליקציה מנוהלת במכשיר Android. כשמקצים תפקיד ספציפי, אפשר להחריג אפליקציה מהגבלות על צריכת החשמל ועל פעילות ברקע, מהשעיה, ממצב שינה (ב-Android מגרסה 14 ואילך) ולהשבית את אמצעי הבקרה של המשתמש (כלומר, כולל פעולות של המשתמש כמו עצירה כפויה וניקוי נתוני האפליקציה) (ב-Android מגרסה 11 ואילך), כדי לאפשר לה לבצע את הפונקציה הקריטית שלה ללא הפרעה. בנוסף, האפליקציה יכולה לקבל הודעה על התפקידים שהוקצו לה, וכך היא יכולה לבצע אתחול עצמי ללא התערבות המשתמש.
במאמר הזהRoleType מפורטים התפקידים באפליקציה וההרשאות המיוחדות שניתנות לכל תפקיד.
דרישות מוקדמות
המכשיר מנוהל על ידי EMM שמבוסס על AMAPI (אין תמיכה ב-EMM שמשתמשים ב-DPC בהתאמה אישית).
הכנת האפליקציה לשימוש בתכונה
צריך לשלב את AMAPI SDK רק אם רוצים שהאפליקציה תקבל התראות על התפקידים שהוקצו לה, כדי שהיא תוכל להפעיל את עצמה (כלומר, הפעלה אוטומטית בלי אינטראקציה של המשתמש).
שילוב עם AMAPI SDK באפליקציה
מידע נוסף על AMAPI SDK ועל הוספה שלו לאפליקציה זמין במדריך לשילוב AMAPI SDK.
מוסיפים את המטא-נתונים הנדרשים למניפסט של האפליקציה
כדי להודיע לאפליקציה על התפקידים שהוקצו לה, מדיניות מכשיר Android (ADP) צריך לדעת את ComponentName של המחלקה שמטמיעה את NotificationReceiverService. צריך לתייג את השירות ב-AndroidManifest.xml בצורה מתאימה כדי ש-ADP יוכל לגלות אותו באופן אוטומטי.
- באפליקציה צריך להיות בדיוק שירות אחד שהוא
enabledויש לוmeta-dataעםandroid:nameששווה ל-com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES - בשירות הזה, צריך להגדיר את
android:exportedבתורtrue - הערך של
android:valueב-meta-dataצריך להיות מחרוזת ריקה
<service
android:name=".MyNotificationReceiverService"
android:exported="true">
<meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES" android:value="" />
</service>
אם אתם בודקים את התפקיד COMPANION_APP, אתם צריכים גם להוסיף את ה-meta-data הבא לשירות שלכם כדי ש-Android Device Policy תוכל לשלוח עדכונים מקומיים של סטטוס הפקודות לאפליקציה:
<meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_COMMAND_STATUS" android:value="" />
יוצרים שירות שמרחיב את NotificationReceiverService (או מעדכנים את השירות הקיים)
יוצרים או מעדכנים את NotificationReceiverService הקיים ומטמיעים AppRolesListener כדי להאזין לתפקידים שהוקצו לאפליקציה. רק getAppRolesListener() נדרש כדי להאזין לתפקידים שהוקצו לאפליקציה. אם לאפליקציה הוקצה תפקיד COMPANION_APP, צריך להטמיע גם את getCommandListener():
import android.util.Log
import com.google.android.managementapi.approles.AppRolesListener
import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.commands.CommandListener
import com.google.android.managementapi.commands.model.Command
import com.google.android.managementapi.notification.NotificationReceiverService
class MyNotificationReceiverService : NotificationReceiverService() {
// If your app wants to listen for roles assigned
override fun getAppRolesListener(): AppRolesListener =
object : AppRolesListener {
override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
val roleTypes = request.roles.map { role -> role.roleType }
Log.i(TAG, "onAppRolesSet: $roleTypes")
return AppRolesSetResponse.getDefaultInstance()
}
}
// If your app wants to listen for local command status updates
// Only relevant for COMPANION_APP role
override fun getCommandListener(): CommandListener {
return object : CommandListener {
override fun onCommandStatusChanged(command: Command) {
Log.i(TAG, "onCommandStatusChanged")
}
}
}
private companion object {
const val TAG = "MyNotificationReceiverService"
}
}
האפליקציה יכולה לקבל כמה התראות אם התפקידים שלה משתנים כמה פעמים. אם כל התפקידים יוסרו, האפליקציה עדיין תקבל התראה עם רשימה ריקה של תפקידים. ההתראה הזו תוציא את האפליקציה ממצב עצירה, ובשילוב עם הפטורים שניתנו לאפליקציה, היא תוכל להפעיל את עצמה בלי אינטראקציה של המשתמש. בזכות ההתראות והפטורים של תפקידי האפליקציה, האפליקציה יכולה להאזין לשידורי ACTION_BOOT_COMPLETED. אם האפליקציה שלכם תלויה בהגדרות האישיות המנוהלות שלה כדי לבצע אתחול, אתם יכולים לקרוא את המאמר הגדרת תצורות מנוהלות כדי ללמוד איך לקרוא את השינויים ולהאזין להם.
החל מגרסה 1.9.0 של AMAPI SDK, כל תפקיד ב-AppRolesSetRequest כולל גם את Role.ExtraCapabilities שהאדמין ממחלקת ה-IT העניק במדיניות. לדוגמה, אפליקציה נלווית יכולה לבדוק אם מותר לה להנפיק פקודת מחיקה מקומית:
import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.common.model.Role
...
override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
val canWipeLocally =
request.roles.any { role ->
role.roleType == Role.RoleType.COMPANION_APP &&
role.extraCapabilities.localDeviceWipeCommand ==
Role.ExtraCapabilities.LocalDeviceWipeCommand.LOCAL_DEVICE_WIPE_COMMAND_ALLOWED
}
Log.i(TAG, "onAppRolesSet: canWipeLocally=$canWipeLocally")
return AppRolesSetResponse.getDefaultInstance()
}
רק האדמין ממחלקת ה-IT יכול להעניק יכולות נוספות. אם מגדירים את extraCapabilities בתפקיד שמעבירים אל EnvironmentClient, הקריאה נכשלת עם InvalidArgumentException.
הקצאת המכשיר עם כללי מדיניות של תפקידים באפליקציה
מפתחי אפליקציות יכולים לבדוק את הקצאת התפקידים באפליקציה שלהם באמצעות EMM או לפי המדריך למתחילים של Android Management API. באמצעות ה-notebook של AMAPI ב-Colab, אתם יכולים לרשום ארגון,ליצור מדיניות ולהקצות מכשיר.
הגדרת המדיניות לאפליקציה באמצעות תפקידים באפליקציה
מגדירים policy עם תפקידי האפליקציה שרוצים שיהיו לאפליקציה, באמצעות ApplicationPolicy.roles.
בדוגמה הבאה מוסבר איך להגדיר את התפקיד לאפליקציות MTD:
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
]
}
]
}
רק התפקיד COMPANION_APP תומך ב-extraCapabilities. כדי לאפשר לאפליקציה הנלווית למחוק את המכשיר או את פרופיל העבודה באופן מקומי, צריך להגדיר את extraCapabilities.localDeviceWipeCommand לערך LOCAL_DEVICE_WIPE_COMMAND_ALLOWED בתפקיד הזה.
לפני הקצאת התפקידים כפי שצוין במדיניות, המערכת תבדוק שטביעת האצבע לאישור מפתח החתימה של האפליקציה במכשיר תואמת לזו שבחנות Play.
אם טביעת האצבע שונה, התפקידים לא יוקצו לאפליקציה ואי-התאימות של NonComplianceReason.APP_SIGNING_CERT_MISMATCH תדווח ל-EMM.
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"signingKeyCerts": [
{ "signingKeyCertFingerprintSha256": "base64-encoded-sha256" }
],
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
]
}
]
}
אם לאפליקציה יש הגדרה מנוהלת, האדמין ממחלקת ה-IT יכול לקבוע הגדרה ראשונית ל-restriction הרלוונטיים במדיניות האפליקציה:
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
],
"managedConfiguration": {
"<key>": "<value>"
}
}
]
}
אימות סטטוס הפטור של הסוללה
אפליקציות עם התפקיד Mobile Threat Defense (MTD) פטורות באופן אוטומטי מהגבלות רגילות על צריכת החשמל ברקע. עם זאת, הפטור הזה מיושם על ידי קטגוריית האפליקציות במצב המתנה, ולא על ידי רשימת ההיתרים של המערכת לחיסכון בחשמל.
כדי לבדוק אם הפטור של האפליקציה פעיל:
import android.app.usage.UsageStatsManager
import android.content.Context
// UsageStatsManager.STANDBY_BUCKET_EXEMPTED is annotated as a @SystemApi. We can redefine it for clarity.
// Define this at the top level of your file, or inside a companion object
private const val STANDBY_BUCKET_EXEMPTED = 5
private fun isAppExemptedFromAppStandbyBucket(): Boolean =
(getSystemService(Context.USAGE_STATS_SERVICE) as? UsageStatsManager)
?.appStandbyBucket == STANDBY_BUCKET_EXEMPTED