1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.provision; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; 20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; 21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION; 22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM; 23 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER; 24 25 import static com.android.provision.Utils.DEFAULT_SETTINGS_PROVISION_DO_MODE; 26 import static com.android.provision.Utils.SETTINGS_PROVISION_DO_MODE; 27 import static com.android.provision.Utils.TAG; 28 import static com.android.provision.Utils.getSettings; 29 30 import android.app.Activity; 31 import android.app.AlertDialog; 32 import android.app.admin.DevicePolicyManager; 33 import android.content.ComponentName; 34 import android.content.Intent; 35 import android.content.pm.PackageManager; 36 import android.os.Bundle; 37 import android.provider.Settings; 38 import android.util.Log; 39 40 /** 41 * Application that sets the provisioned bit, like {@code SetupWizard} does. 42 * 43 * <p>By default, it silently provisions the device, but it can also be used to provision 44 * {@code DeviceOwner}. For example, to set the {@code TestDPC} app, run the steps below: 45 * <pre><code> 46 adb root 47 adb install PATH_TO_TESTDPC_APK 48 adb shell settings put secure tmp_provision_set_do 1 49 adb shell settings put secure tmp_provision_package com.afwsamples.testdpc 50 adb shell settings put secure tmp_provision_receiver com.afwsamples.testdpc.DeviceAdminReceiver 51 adb shell settings put secure tmp_provision_trigger 2 52 adb shell rm /data/system/device_policies.xml 53 adb shell settings put global device_provisioned 0 54 adb shell settings put secure user_setup_complete 0 55 adb shell pm enable com.android.provision 56 adb shell pm enable com.android.provision/.DefaultActivity 57 adb shell stop && adb shell start 58 59 // You might also need to run: 60 adb shell am start com.android.provision/.DefaultActivity 61 62 * </code></pre> 63 */ 64 public class DefaultActivity extends Activity { 65 66 // TODO(b/170333009): copied from ManagedProvisioning app, as they're hidden; 67 private static final String PROVISION_FINALIZATION_INSIDE_SUW = 68 "android.app.action.PROVISION_FINALIZATION_INSIDE_SUW"; 69 private static final int RESULT_CODE_PROFILE_OWNER_SET = 122; 70 private static final int RESULT_CODE_DEVICE_OWNER_SET = 123; 71 72 private static final int REQUEST_CODE_STEP1 = 42; 73 private static final int REQUEST_CODE_STEP2_PO = 43; 74 private static final int REQUEST_CODE_STEP2_DO = 44; 75 76 @Override onCreate(Bundle icicle)77 protected void onCreate(Bundle icicle) { 78 super.onCreate(icicle); 79 80 boolean provisionDeviceOwner = getSettings(getContentResolver(), SETTINGS_PROVISION_DO_MODE, 81 DEFAULT_SETTINGS_PROVISION_DO_MODE) == 1; 82 83 if (provisionDeviceOwner) { 84 provisionDeviceOwner(); 85 return; 86 } 87 finishSetup(); 88 } 89 finishSetup()90 private void finishSetup() { 91 setProvisioningState(); 92 disableSelfAndFinish(); 93 } 94 setProvisioningState()95 private void setProvisioningState() { 96 Log.i(TAG, "Setting provisioning state"); 97 // Add a persistent setting to allow other apps to know the device has been provisioned. 98 Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1); 99 Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1); 100 } 101 disableSelfAndFinish()102 private void disableSelfAndFinish() { 103 // remove this activity from the package manager. 104 PackageManager pm = getPackageManager(); 105 ComponentName name = new ComponentName(this, DefaultActivity.class); 106 Log.i(TAG, "Disabling itself (" + name + ")"); 107 pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 108 PackageManager.DONT_KILL_APP); 109 // terminate the activity. 110 finish(); 111 } 112 provisionDeviceOwner()113 private void provisionDeviceOwner() { 114 if (!getPackageManager() 115 .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { 116 Log.e(TAG, "Cannot set up device owner because device does not have the " 117 + PackageManager.FEATURE_DEVICE_ADMIN + " feature"); 118 finishSetup(); 119 return; 120 } 121 DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); 122 if (!dpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE)) { 123 Log.e(TAG, "DeviceOwner provisioning is not allowed, most like device is already " 124 + "provisioned"); 125 finishSetup(); 126 return; 127 } 128 129 DpcInfo dpcInfo = new DpcInfo(getContentResolver()); 130 Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE); 131 intent.putExtra(EXTRA_PROVISIONING_TRIGGER, dpcInfo.trigger); 132 intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, 133 dpcInfo.getReceiverComponentName()); 134 if (dpcInfo.checkSum != null) { 135 intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM, dpcInfo.checkSum); 136 } 137 if (dpcInfo.downloadUrl != null) { 138 intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, 139 dpcInfo.downloadUrl); 140 } 141 142 Log.i(TAG, "Provisioning device with " + dpcInfo + ". Intent: " + intent); 143 startActivityForResult(intent, REQUEST_CODE_STEP1); 144 } 145 146 @Override onActivityResult(int requestCode, int resultCode, Intent data)147 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 148 Log.d(TAG, "onActivityResult(): request=" + requestCode + ", result=" 149 + resultCodeToString(resultCode) + ", data=" + data); 150 151 switch (requestCode) { 152 case REQUEST_CODE_STEP1: 153 onProvisioningStep1Result(resultCode); 154 break; 155 case REQUEST_CODE_STEP2_PO: 156 case REQUEST_CODE_STEP2_DO: 157 onProvisioningStep2Result(requestCode, resultCode); 158 break; 159 default: 160 showErrorMessage("onActivityResult(): invalid request code " + requestCode); 161 } 162 } 163 onProvisioningStep1Result(int resultCode)164 private void onProvisioningStep1Result(int resultCode) { 165 int requestCodeStep2; 166 switch (resultCode) { 167 case RESULT_CODE_PROFILE_OWNER_SET: 168 requestCodeStep2 = REQUEST_CODE_STEP2_PO; 169 break; 170 case RESULT_CODE_DEVICE_OWNER_SET: 171 requestCodeStep2 = REQUEST_CODE_STEP2_DO; 172 break; 173 default: 174 factoryReset("invalid response from " 175 + ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE + ": " 176 + resultCodeToString(resultCode)); 177 return; 178 } 179 Intent intent = new Intent(PROVISION_FINALIZATION_INSIDE_SUW) 180 .addCategory(Intent.CATEGORY_DEFAULT); 181 Log.i(TAG, "Finalizing DPC with " + intent); 182 startActivityForResult(intent, requestCodeStep2); 183 } 184 onProvisioningStep2Result(int requestCode, int resultCode)185 private void onProvisioningStep2Result(int requestCode, int resultCode) { 186 // Must set state before launching the intent that finalize the DPC, because the DPC 187 // implementation might not remove the back button 188 setProvisioningState(); 189 190 boolean doMode = requestCode == REQUEST_CODE_STEP2_DO; 191 if (resultCode != RESULT_OK) { 192 factoryReset("invalid response from " + PROVISION_FINALIZATION_INSIDE_SUW + ": " 193 + resultCodeToString(resultCode)); 194 return; 195 } 196 197 Log.i(TAG, (doMode ? "Device owner" : "Profile owner") + " mode provisioned!"); 198 disableSelfAndFinish(); 199 } 200 resultCodeToString(int resultCode)201 private static String resultCodeToString(int resultCode) { 202 StringBuilder result = new StringBuilder(); 203 switch (resultCode) { 204 case RESULT_OK: 205 result.append("RESULT_OK"); 206 break; 207 case RESULT_CANCELED: 208 result.append("RESULT_CANCELED"); 209 break; 210 case RESULT_FIRST_USER: 211 result.append("RESULT_FIRST_USER"); 212 break; 213 case RESULT_CODE_PROFILE_OWNER_SET: 214 result.append("RESULT_CODE_PROFILE_OWNER_SET"); 215 break; 216 case RESULT_CODE_DEVICE_OWNER_SET: 217 result.append("RESULT_CODE_DEVICE_OWNER_SET"); 218 break; 219 default: 220 result.append("UNKNOWN_CODE"); 221 } 222 return result.append('(').append(resultCode).append(')').toString(); 223 } 224 showErrorMessage(String message)225 private void showErrorMessage(String message) { 226 Log.e(TAG, "Error: " + message); 227 } 228 factoryReset(String reason)229 private void factoryReset(String reason) { 230 new AlertDialog.Builder(this) 231 .setMessage("Device owner provisioning failed (" + reason 232 + ") and device must be factory reset") 233 .setPositiveButton("Reset", (d, w) -> sendFactoryResetIntent(reason)) 234 .setOnDismissListener((d) -> sendFactoryResetIntent(reason)) 235 .show(); 236 } 237 sendFactoryResetIntent(String reason)238 private void sendFactoryResetIntent(String reason) { 239 Log.e(TAG, "Factory resetting: " + reason); 240 Intent intent = new Intent(Intent.ACTION_FACTORY_RESET); 241 intent.setPackage("android"); 242 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 243 intent.putExtra(Intent.EXTRA_REASON, reason); 244 245 sendBroadcast(intent); 246 247 // Just in case the factory reset request fails... 248 finishSetup(); 249 } 250 } 251