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