Home | History | Annotate | Download | only in managedprovisioning
      1 /*
      2  * Copyright 2014, 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.managedprovisioning;
     18 
     19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE;
     20 
     21 import android.app.AlarmManager;
     22 import android.app.Service;
     23 import android.app.admin.DevicePolicyManager;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.pm.PackageManager;
     28 import android.os.Bundle;
     29 import android.os.IBinder;
     30 import android.os.Process;
     31 import android.os.UserHandle;
     32 import android.os.UserManager;
     33 import android.support.v4.content.LocalBroadcastManager;
     34 
     35 import com.android.internal.app.LocalePicker;
     36 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
     37 import com.android.managedprovisioning.common.Utils;
     38 import com.android.managedprovisioning.model.ProvisioningParams;
     39 import com.android.managedprovisioning.task.AddWifiNetworkTask;
     40 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask;
     41 import com.android.managedprovisioning.task.DisallowAddUserTask;
     42 import com.android.managedprovisioning.task.DownloadPackageTask;
     43 import com.android.managedprovisioning.task.InstallPackageTask;
     44 import com.android.managedprovisioning.task.SetDevicePolicyTask;
     45 
     46 import java.util.Locale;
     47 
     48 /**
     49  * This service does the work for the DeviceOwnerProvisioningActivity.
     50  * Feedback is sent back to the activity via intents.
     51  *
     52  * <p>
     53  * If the corresponding activity is killed and restarted, the service is
     54  * called twice. The service will not start the provisioning flow a second time, but instead
     55  * send a status update to the activity.
     56  * </p>
     57  */
     58 public class DeviceOwnerProvisioningService extends Service {
     59     private static final boolean DEBUG = false; // To control logging.
     60 
     61     private static final String DEVICE_OWNER = "deviceOwner";
     62 
     63     /**
     64      * Intent action to activate the CDMA phone connection by OTASP.
     65      * This is not necessary for a GSM phone connection, which is activated automatically.
     66      * String must agree with the constants in com.android.phone.InCallScreenShowActivation.
     67      */
     68     private static final String ACTION_PERFORM_CDMA_PROVISIONING =
     69             "com.android.phone.PERFORM_CDMA_PROVISIONING";
     70 
     71     // Intent actions and extras for communication from DeviceOwnerProvisioningService to Activity.
     72     protected static final String ACTION_PROVISIONING_SUCCESS =
     73             "com.android.managedprovisioning.provisioning_success";
     74     protected static final String ACTION_PROVISIONING_ERROR =
     75             "com.android.managedprovisioning.error";
     76     protected static final String EXTRA_USER_VISIBLE_ERROR_ID_KEY =
     77             "UserVisibleErrorMessage-Id";
     78     protected static final String EXTRA_FACTORY_RESET_REQUIRED =
     79             "FactoryResetRequired";
     80     protected static final String ACTION_PROGRESS_UPDATE =
     81             "com.android.managedprovisioning.progress_update";
     82     protected static final String EXTRA_PROGRESS_MESSAGE_ID_KEY =
     83             "ProgressMessageId";
     84     protected static final String ACTION_REQUEST_WIFI_PICK =
     85             "com.android.managedprovisioning.request_wifi_pick";
     86 
     87     // Indicates whether provisioning has started.
     88     private boolean mProvisioningInFlight = false;
     89 
     90     // MessageId of the last progress message.
     91     private int mLastProgressMessage = -1;
     92 
     93     // MessageId of the last error message.
     94     private int mLastErrorMessage = -1;
     95 
     96     // Indicates whether reverting the provisioning process up till now requires a factory reset.
     97     // Is false at the start and flips to true after the first irrevertible action.
     98     private boolean mFactoryResetRequired = false;
     99 
    100     // Indicates whether provisioning has finished successfully (service waiting to stop).
    101     private volatile boolean mDone = false;
    102 
    103     // Provisioning tasks.
    104     private AddWifiNetworkTask mAddWifiNetworkTask;
    105     private DownloadPackageTask mDownloadPackageTask;
    106     private InstallPackageTask mInstallPackageTask;
    107     private SetDevicePolicyTask mSetDevicePolicyTask;
    108     private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask;
    109     private DisallowAddUserTask mDisallowAddUserTask;
    110 
    111     private ProvisioningParams mParams;
    112 
    113     private final Utils mUtils = new Utils();
    114 
    115     @Override
    116     public int onStartCommand(final Intent intent, int flags, int startId) {
    117         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND.");
    118 
    119         synchronized (this) { // Make operations on mProvisioningInFlight atomic.
    120             if (mProvisioningInFlight) {
    121                 if (DEBUG) ProvisionLogger.logd("Provisioning already in flight.");
    122 
    123                 sendProgressUpdateToActivity();
    124 
    125                 // Send error message if currently in error state.
    126                 if (mLastErrorMessage >= 0) {
    127                     sendError();
    128                 }
    129 
    130                 // Send success if provisioning was successful.
    131                 if (mDone) {
    132                     onProvisioningSuccess();
    133                 }
    134             } else {
    135                 mProvisioningInFlight = true;
    136                 if (DEBUG) ProvisionLogger.logd("First start of the service.");
    137                 progressUpdate(R.string.progress_data_process);
    138 
    139                 // Load the ProvisioningParams (from message in Intent).
    140                 mParams = (ProvisioningParams) intent.getParcelableExtra(
    141                         ProvisioningParams.EXTRA_PROVISIONING_PARAMS);
    142 
    143                 // Do the work on a separate thread.
    144                 new Thread(new Runnable() {
    145                     public void run() {
    146                         initializeProvisioningEnvironment(mParams);
    147                         startDeviceOwnerProvisioning(mParams);
    148                     }
    149                 }).start();
    150             }
    151         }
    152         return START_NOT_STICKY;
    153     }
    154 
    155     /**
    156      * This is the core method of this class. It goes through every provisioning step.
    157      * Each task checks if it is required and executes if it is.
    158      */
    159     private void startDeviceOwnerProvisioning(final ProvisioningParams params) {
    160         if (DEBUG) ProvisionLogger.logd("Starting device owner provisioning");
    161 
    162         // Construct Tasks. Do not start them yet.
    163         mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.wifiInfo,
    164                 new AddWifiNetworkTask.Callback() {
    165                     @Override
    166                     public void onSuccess() {
    167                         progressUpdate(R.string.progress_download);
    168                         mDownloadPackageTask.run();
    169                     }
    170 
    171                     @Override
    172                     public void onError(){
    173                         error(R.string.device_owner_error_wifi,
    174                                 false /* do not require factory reset */);
    175                     }
    176                 });
    177 
    178         mDownloadPackageTask = new DownloadPackageTask(this,
    179                 new DownloadPackageTask.Callback() {
    180                     @Override
    181                     public void onSuccess() {
    182                         progressUpdate(R.string.progress_install);
    183                         mInstallPackageTask.addInstallIfNecessary(
    184                                 params.inferDeviceAdminPackageName(),
    185                                 mDownloadPackageTask.getDownloadedPackageLocation(DEVICE_OWNER));
    186                         mInstallPackageTask.run();
    187                     }
    188 
    189                     @Override
    190                     public void onError(int errorCode) {
    191                         switch(errorCode) {
    192                             case DownloadPackageTask.ERROR_HASH_MISMATCH:
    193                                 error(R.string.device_owner_error_hash_mismatch);
    194                                 break;
    195                             case DownloadPackageTask.ERROR_DOWNLOAD_FAILED:
    196                                 error(R.string.device_owner_error_download_failed);
    197                                 break;
    198                             default:
    199                                 error(R.string.device_owner_error_general);
    200                                 break;
    201                         }
    202                     }
    203                 });
    204 
    205         // Add packages to download to the DownloadPackageTask.
    206         mDownloadPackageTask.addDownloadIfNecessary(params.inferDeviceAdminPackageName(),
    207                 params.deviceAdminDownloadInfo, DEVICE_OWNER);
    208 
    209         mInstallPackageTask = new InstallPackageTask(this,
    210                 new InstallPackageTask.Callback() {
    211                     @Override
    212                     public void onSuccess() {
    213                         progressUpdate(R.string.progress_set_owner);
    214                         try {
    215                             // Now that the app has been installed, we can look for the device admin
    216                             // component in it.
    217                             mSetDevicePolicyTask.run(mParams.inferDeviceAdminComponentName(
    218                                     DeviceOwnerProvisioningService.this));
    219                         } catch (IllegalProvisioningArgumentException e) {
    220                             error(R.string.device_owner_error_general);
    221                             ProvisionLogger.loge("Failed to infer the device admin component name",
    222                                     e);
    223                             return;
    224                         }
    225                     }
    226 
    227                     @Override
    228                     public void onError(int errorCode) {
    229                         switch(errorCode) {
    230                             case InstallPackageTask.ERROR_PACKAGE_INVALID:
    231                                 error(R.string.device_owner_error_package_invalid);
    232                                 break;
    233                             case InstallPackageTask.ERROR_INSTALLATION_FAILED:
    234                                 error(R.string.device_owner_error_installation_failed);
    235                                 break;
    236                             default:
    237                                 error(R.string.device_owner_error_general);
    238                                 break;
    239                         }
    240                     }
    241                 });
    242 
    243         mSetDevicePolicyTask = new SetDevicePolicyTask(this,
    244                 getResources().getString(R.string.default_owned_device_username),
    245                 new SetDevicePolicyTask.Callback() {
    246                     @Override
    247                     public void onSuccess() {
    248                         mDeleteNonRequiredAppsTask.run();
    249                     }
    250 
    251                     @Override
    252                     public void onError() {
    253                         error(R.string.device_owner_error_general);
    254                     }
    255                 });
    256 
    257         // For split system user devices that will have a system device owner, don't adjust the set
    258         // of enabled packages in the system user as we expect the right set of packages to be
    259         // enabled for the system user out of the box. For other devices, the set of available
    260         // packages can vary depending on management state.
    261         boolean leaveAllSystemAppsEnabled = params.leaveAllSystemAppsEnabled ||
    262                 params.provisioningAction.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE);
    263         mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask(
    264                 this, params.inferDeviceAdminPackageName(),
    265                 DeleteNonRequiredAppsTask.DEVICE_OWNER, true /* creating new profile */,
    266                 UserHandle.myUserId(), leaveAllSystemAppsEnabled,
    267                 new DeleteNonRequiredAppsTask.Callback() {
    268                     @Override
    269                     public void onSuccess() {
    270                         mDisallowAddUserTask.maybeDisallowAddUsers();
    271 
    272                         // Done with provisioning. Success.
    273                         onProvisioningSuccess();
    274                     }
    275 
    276                     @Override
    277                     public void onError() {
    278                         error(R.string.device_owner_error_general);
    279                     }
    280                 });
    281 
    282         mDisallowAddUserTask = new DisallowAddUserTask((UserManager) getSystemService(USER_SERVICE),
    283                 UserHandle.myUserId(), UserManager.isSplitSystemUser());
    284 
    285         // Start first task, which starts next task in its callback, etc.
    286         progressUpdate(R.string.progress_connect_to_wifi);
    287         mAddWifiNetworkTask.run();
    288     }
    289 
    290     private void error(int dialogMessage) {
    291         error(dialogMessage, true /* require factory reset */);
    292     }
    293 
    294     private void error(int dialogMessage, boolean factoryResetRequired) {
    295         mLastErrorMessage = dialogMessage;
    296         if (factoryResetRequired) {
    297             mFactoryResetRequired = true;
    298         }
    299         sendError();
    300         // Wait for stopService() call from the activity.
    301     }
    302 
    303     private void sendError() {
    304         if (DEBUG) {
    305             ProvisionLogger.logd("Reporting Error: " + getResources()
    306                 .getString(mLastErrorMessage));
    307         }
    308         Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
    309         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    310         intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage);
    311         intent.putExtra(EXTRA_FACTORY_RESET_REQUIRED, mFactoryResetRequired);
    312         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    313     }
    314 
    315     private void progressUpdate(int progressMessage) {
    316         if (DEBUG) {
    317             ProvisionLogger.logd("Reporting progress update: " + getResources()
    318                 .getString(progressMessage));
    319         }
    320         mLastProgressMessage = progressMessage;
    321         sendProgressUpdateToActivity();
    322     }
    323 
    324     private void sendProgressUpdateToActivity() {
    325         Intent intent = new Intent(ACTION_PROGRESS_UPDATE);
    326         intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage);
    327         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    328         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    329     }
    330 
    331     private void onProvisioningSuccess() {
    332         // Copying an account needs to happen late in the provisioning process to allow the current
    333         // user to be started, but before we tell the MDM that provisioning succeeded.
    334         maybeCopyAccount();
    335 
    336         if (DEBUG) ProvisionLogger.logd("Reporting success.");
    337         mDone = true;
    338 
    339         // Set DPM userProvisioningState appropriately and persists mParams for use during
    340         // FinalizationActivity if necessary.
    341         mUtils.markUserProvisioningStateInitiallyDone(this, mParams);
    342 
    343         Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
    344         successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    345         LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent);
    346         // Wait for stopService() call from the activity.
    347     }
    348 
    349     private void maybeCopyAccount() {
    350         if (!UserManager.isSplitSystemUser()) {
    351             // Only one user involved in this case.
    352             return;
    353         }
    354 
    355         mUtils.maybeCopyAccount(DeviceOwnerProvisioningService.this,
    356                 mParams.accountToMigrate, UserHandle.SYSTEM,
    357                 Process.myUserHandle());
    358     }
    359 
    360     private void initializeProvisioningEnvironment(ProvisioningParams params) {
    361         setTimeAndTimezone(params.timeZone, params.localTime);
    362         setLocale(params.locale);
    363 
    364         // Start CDMA activation to enable phone calls.
    365         final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING);
    366         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    367         if (DEBUG) ProvisionLogger.logd("Starting cdma activation activity");
    368         startActivity(intent); // Activity will be a Nop if not a CDMA device.
    369     }
    370 
    371     private void setTimeAndTimezone(String timeZone, long localTime) {
    372         try {
    373             final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    374             if (timeZone != null) {
    375                 if (DEBUG) ProvisionLogger.logd("Setting time zone to " + timeZone);
    376                 am.setTimeZone(timeZone);
    377             }
    378             if (localTime > 0) {
    379                 if (DEBUG) ProvisionLogger.logd("Setting time to " + localTime);
    380                 am.setTime(localTime);
    381             }
    382         } catch (Exception e) {
    383             ProvisionLogger.loge("Alarm manager failed to set the system time/timezone.");
    384             // Do not stop provisioning process, but ignore this error.
    385         }
    386     }
    387 
    388     private void setLocale(Locale locale) {
    389         if (locale == null || locale.equals(Locale.getDefault())) {
    390             return;
    391         }
    392         try {
    393             if (DEBUG) ProvisionLogger.logd("Setting locale to " + locale);
    394             // If locale is different from current locale this results in a configuration change,
    395             // which will trigger the restarting of the activity.
    396             LocalePicker.updateLocale(locale);
    397         } catch (Exception e) {
    398             ProvisionLogger.loge("Failed to set the system locale.");
    399             // Do not stop provisioning process, but ignore this error.
    400         }
    401     }
    402 
    403     @Override
    404     public void onCreate () {
    405         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONCREATE.");
    406     }
    407 
    408     @Override
    409     public void onDestroy () {
    410         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONDESTROY");
    411         if (mAddWifiNetworkTask != null) {
    412             mAddWifiNetworkTask.cleanUp();
    413         }
    414         if (mDownloadPackageTask != null) {
    415             mDownloadPackageTask.cleanUp();
    416         }
    417     }
    418 
    419     @Override
    420     public IBinder onBind(Intent intent) {
    421         return null;
    422     }
    423 }
    424