We have a fleet of Samsung XCover 4 devices that we use for time tracking. Initially, we used the NFC method to provision the devices and take over device ownership. However, we needed a way to update the time tracking app OTA silently.
To achieve this, we factory reset the devices and rooted them with the help of Magisk. With root access, our update app was able to update the time tracking app silently over the air.
To ensure that the devices remained in kiosk mode, I made the "update app" the device admin and whitelisted the time tracking app using the following command:
dpm set-device-owner <package-name>/.DeviceAdminReceiver
The devices worked perfectly, and users could not exit kiosk mode. However, we encountered an issue with unplanned reboots, such as when the battery ran out. The devices would remain in a boot loop, and Android Recovery would appear. We could only save them by flashing an image through ODIN.
We tried disabling the device admin using the following command:
dpm remove-active-admin <package-name>/.DeviceAdminReceiver
and then rebooting the devices, which allowed them to start normally. However, this was not a practical solution for planned reboots, as we couldn't guarantee that the device admin would be disabled beforehand.
So to sum everything find. Setting the device owner programtically and then rebooting causes a bootloop. Setting the device owner but then removing it and then booting, is fine.
If anyone has encountered a similar problem and knows how to help, we would greatly appreciate it.
Additional notes:
The Samsung XCover 4 devices are rooted, run on Android 9 with the newest Samsung image from 2020. The XML files /data/system/device_owner_2.xml & /data/system/device_policies.xml were in place and looked fine.
Edit:
My AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.STATUS_BAR" />
<uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.PREVENT_POWER_KEY" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.UpdateServices"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
android:testOnly="false"
tools:targetApi="29">
<service
android:enabled="true"
android:name="c.m.updateservice.UpdateService" >
</service>
<activity
android:name="c.m.updateservice.MainActivity"
android:label="@string/app_name"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:enabled="true" android:name="c.m.updateservice.StartReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<receiver android:enabled="true" android:name="c.m.updateservice.RebootReceiver">
<intent-filter>
<action android:name="android.intent.action.REBOOT_ACTION" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<action android:name="android.intent.action.ACTION_REBOOT" />
<action android:name="android.intent.action.ACTION_BATTERY_LOW" />
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<receiver
android:name="c.m.updateservice.DeviceAdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_receiver" />
<intent-filter>
<action android:name="android.intent.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>
</application>
</manifest>
device_admin_receiver.xml
<?xml version="1.0" encoding="utf-8"?>
<device-admin>
<uses-policies>
<disable-keyguard-features/>
</uses-policies>
</device-admin>
I compared the adb log file of my phone booting fine and of the bootloop and I am also including the part which seems to be responsible for the bootloop:
05-01 23:54:51.763 3047 3057 E ActivityManager: Activity Manager Crash. UID:10162 PID:3702 TRANS:8
05-01 23:54:51.763 3047 3057 E ActivityManager: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.ComponentName.flattenToShortString()' on a null object reference
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityRecord$Token.<init>(ActivityRecord.java:990)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityRecord.<init>(ActivityRecord.java:1063)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStarter.startActivity(ActivityStarter.java:1113)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStarter.startActivity(ActivityStarter.java:680)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStarter.execute(ActivityStarter.java:631)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStartController.startHomeActivity(ActivityStartController.java:190)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityManagerService.startHomeActivityLocked(ActivityManagerService.java:6181)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStackSupervisor.resumeHomeStackTask(ActivityStackSupervisor.java:973)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStackSupervisor.resumeHomeStackTask(ActivityStackSupervisor.java:943)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityInNextFocusableStack(ActivityStack.java:3352)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2830)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2791)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2729)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2701)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2680)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2655)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStack.finishCurrentActivityLocked(ActivityStack.java:4587)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:4450)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.TaskRecord.performClearTaskAtIndexLocked(TaskRecord.java:1608)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.TaskRecord.removeTaskActivitiesLocked(TaskRecord.java:1700)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityStackSupervisor.removeTaskByIdLocked(ActivityStackSupervisor.java:3744)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityManagerService.finishActivity(ActivityManagerService.java:7472)
05-01 23:54:51.763 3047 3057 E ActivityManager: at android.app.IActivityManager$Stub.onTransact$finishActivity$(IActivityManager.java:10915)
05-01 23:54:51.763 3047 3057 E ActivityManager: at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:122)
05-01 23:54:51.763 3047 3057 E ActivityManager: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:4183)
05-01 23:54:51.763 3047 3057 E ActivityManager: at android.os.Binder.execTransact(Binder.java:739)
05-01 23:54:51.767 3047 3081 D InputManager-JNI: setVirtualDisplayViewports: return because there is no change
05-01 23:54:51.767 3709 3709 D CarrierConfigLoader: CarrierConfigLoader has started
05-01 23:54:51.767 3709 3709 V PhoneGlobals: onCreate() : PhoneFactory.makeDefaultPhones
05-01 23:54:51.769 3047 3047 D ConnectivityManager: requestNetwork; CallingUid : 1000, CallingPid : 3047, PackageName : android
05-01 23:54:51.769 3702 3702 E BM : java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.ComponentName.flattenToShortString()' on a null object reference
05-01 23:54:51.769 3702 3702 E BM : at android.os.Parcel.createException(Parcel.java:1972)
05-01 23:54:51.769 3702 3702 E BM : at android.os.Parcel.readException(Parcel.java:1934)
05-01 23:54:51.769 3702 3702 E BM : at android.os.Parcel.readException(Parcel.java:1884)
05-01 23:54:51.769 3702 3702 E BM : at android.app.IActivityManager$Stub$Proxy.finishActivity(IActivityManager.java:3643)
05-01 23:54:51.769 3702 3702 E BM : at android.app.Activity.finish(Activity.java:5726)
05-01 23:54:51.769 3702 3702 E BM : at android.app.Activity.finishAndRemoveTask(Activity.java:5853)
05-01 23:54:51.769 3702 3702 E BM : at com.topjohnwu.magisk.ui.surequest.SuRequestActivity.finish(Unknown Source:0)
05-01 23:54:51.769 3702 3702 E BM : at a.wI.O(SourceFile:46)
05-01 23:54:51.769 3702 3702 E BM : at a.hr.n(SourceFile:6)
05-01 23:54:51.769 3702 3702 E BM : at a.HK.run(SourceFile:110)
05-01 23:54:51.769 3702 3702 E BM : at android.os.Handler.handleCallback(Handler.java:873)
05-01 23:54:51.769 3702 3702 E BM : at android.os.Handler.dispatchMessage(Handler.java:99)
05-01 23:54:51.769 3702 3702 E BM : at android.os.Looper.loop(Looper.java:214)
05-01 23:54:51.769 3702 3702 E BM : at android.app.ActivityThread.main(ActivityThread.java:7156)
05-01 23:54:51.769 3702 3702 E BM : at java.lang.reflect.Method.invoke(Native Method)
05-01 23:54:51.769 3702 3702 E BM : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
05-01 23:54:51.769 3702 3702 E BM : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
05-01 23:54:51.769 3702 3702 E BM : Suppressed: a.ND: [jr{Cancelling}@4cb9c37, Dispatchers.Main.immediate]
05-01 23:54:51.769 3702 3702 E BM : Caused by: android.os.RemoteException: Remote stack trace:
05-01 23:54:51.769 3702 3702 E BM : at com.android.server.am.ActivityRecord$Token.<init>(ActivityRecord.java:990)
05-01 23:54:51.769 3702 3702 E BM : at com.android.server.am.ActivityRecord.<init>(ActivityRecord.java:1063)
05-01 23:54:51.769 3702 3702 E BM : at com.android.server.am.ActivityStarter.startActivity(ActivityStarter.java:1113)
05-01 23:54:51.769 3702 3702 E BM : at com.android.server.am.ActivityStarter.startActivity(ActivityStarter.java:680)
05-01 23:54:51.769 3702 3702 E BM : at com.android.server.am.ActivityStarter.execute(ActivityStarter.java:631)