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.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
     20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
     21 
     22 import android.app.AlarmManager;
     23 import android.app.Service;
     24 import android.content.BroadcastReceiver;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.content.pm.PackageManager;
     30 import android.os.Bundle;
     31 import android.os.IBinder;
     32 import android.os.UserHandle;
     33 import android.support.v4.content.LocalBroadcastManager;
     34 import android.text.TextUtils;
     35 
     36 import com.android.internal.app.LocalePicker;
     37 import com.android.managedprovisioning.task.AddWifiNetworkTask;
     38 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask;
     39 import com.android.managedprovisioning.task.DownloadPackageTask;
     40 import com.android.managedprovisioning.task.InstallPackageTask;
     41 import com.android.managedprovisioning.task.SetDevicePolicyTask;
     42 
     43 import java.lang.Runnable;
     44 import java.util.Locale;
     45 
     46 /**
     47  * This service does the work for the DeviceOwnerProvisioningActivity.
     48  * Feedback is sent back to the activity via intents.
     49  *
     50  * <p>
     51  * If the corresponding activity is killed and restarted, the service is
     52  * called twice. The service will not start the provisioning flow a second time, but instead
     53  * send a status update to the activity.
     54  * </p>
     55  */
     56 public class DeviceOwnerProvisioningService extends Service {
     57     private static final boolean DEBUG = false; // To control logging.
     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 EXTRA_PROVISIONING_PARAMS =
     69             "ProvisioningParams";
     70 
     71     // Intent actions and extras for communication from DeviceOwnerProvisioningActivity to Service.
     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 ACTION_PROGRESS_UPDATE =
     79             "com.android.managedprovisioning.progress_update";
     80     protected static final String EXTRA_PROGRESS_MESSAGE_ID_KEY =
     81             "ProgressMessageId";
     82     protected static final String ACTION_REQUEST_WIFI_PICK =
     83             "com.android.managedprovisioning.request_wifi_pick";
     84 
     85     // Intent action used by the HomeReceiverActivity to notify this Service that a HOME intent was
     86     // received, which indicates that the Setup wizard has closed after provisioning completed.
     87     protected static final String ACTION_HOME_INDIRECT =
     88             "com.android.managedprovisioning.home_indirect";
     89 
     90     // Indicates whether provisioning has started.
     91     private boolean mProvisioningInFlight = false;
     92 
     93     // MessageId of the last progress message.
     94     private int mLastProgressMessage = -1;
     95 
     96     // MessageId of the last error message.
     97     private int mLastErrorMessage = -1;
     98 
     99     // Indicates whether provisioning has finished succesfully (service waiting to stop).
    100     private boolean mDone = false;
    101 
    102     // Provisioning tasks.
    103     private AddWifiNetworkTask mAddWifiNetworkTask;
    104     private DownloadPackageTask mDownloadPackageTask;
    105     private InstallPackageTask mInstallPackageTask;
    106     private SetDevicePolicyTask mSetDevicePolicyTask;
    107     private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask;
    108 
    109     private ProvisioningParams mParams;
    110 
    111     private BroadcastReceiver mIndirectHomeReceiver;
    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 succesful.
    129                 if (mDone) {
    130                     onProvisioningSuccess(mParams.mDeviceAdminPackageName);
    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(EXTRA_PROVISIONING_PARAMS);
    139 
    140                 registerHomeIntentReceiver();
    141 
    142                 // Do the work on a separate thread.
    143                 new Thread(new Runnable() {
    144                         public void run() {
    145                             initializeProvisioningEnvironment(mParams);
    146                             startDeviceOwnerProvisioning(mParams);
    147                         }
    148                     }).start();
    149             }
    150         }
    151         return START_NOT_STICKY;
    152     }
    153 
    154     // Register the receiver for the ACTION_HOME_INDIRECT intent.
    155     // The ACTION_HOME_INDIRECT intent is used to notify this service that the home intent was send.
    156     // After receiving that intent we send the complete intent to the mdm.
    157     // Note: if we would send the complete intent earlier, the home intent can close the mdm.
    158     private void registerHomeIntentReceiver() {
    159         mIndirectHomeReceiver = new IndirectHomeReceiver();
    160         IntentFilter filter = new IntentFilter();
    161         filter.addAction(DeviceOwnerProvisioningService.ACTION_HOME_INDIRECT);
    162         LocalBroadcastManager.getInstance(this).registerReceiver(mIndirectHomeReceiver, filter);
    163     }
    164 
    165     class IndirectHomeReceiver extends BroadcastReceiver {
    166         @Override
    167         public void onReceive(Context context, Intent intent) {
    168             if (!mDone) {
    169                 return;
    170             }
    171 
    172             // Disable the HomeReceiverActivity. It's no longer of use.
    173             PackageManager pm = getPackageManager();
    174             pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this,
    175                             HomeReceiverActivity.class), PackageManager
    176                     .COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    177 
    178             // Send complete intent to mdm.
    179             Intent result = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE);
    180             result.setPackage(mParams.mDeviceAdminPackageName);
    181             result.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES |
    182                     Intent.FLAG_RECEIVER_FOREGROUND);
    183             if (mParams.mAdminExtrasBundle != null) {
    184                 result.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
    185                         mParams.mAdminExtrasBundle);
    186             }
    187             sendBroadcast(result);
    188             stopSelf();
    189         }
    190     }
    191 
    192 
    193     /**
    194      * This is the core method of this class. It goes through every provisioning step.
    195      */
    196     private void startDeviceOwnerProvisioning(final ProvisioningParams params) {
    197         if (DEBUG) ProvisionLogger.logd("Starting device owner provisioning");
    198 
    199         // Construct Tasks. Do not start them yet.
    200         if (TextUtils.isEmpty(params.mWifiSsid)) {
    201             mAddWifiNetworkTask = null;
    202         } else {
    203             mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.mWifiSsid,
    204                     params.mWifiHidden, params.mWifiSecurityType, params.mWifiPassword,
    205                     params.mWifiProxyHost, params.mWifiProxyPort, params.mWifiProxyBypassHosts,
    206                     params.mWifiPacUrl, new AddWifiNetworkTask.Callback() {
    207                             @Override
    208                             public void onSuccess() {
    209                                 if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
    210                                     // Download, install, set as device owner, delete apps.
    211                                     progressUpdate(R.string.progress_download);
    212                                     mDownloadPackageTask.run();
    213                                 } else {
    214                                     // Device Admin will not be downloaded (but is already present):
    215                                     // Just set as device owner, delete apps.
    216                                     progressUpdate(R.string.progress_set_owner);
    217                                     mSetDevicePolicyTask.run();
    218                                 }
    219                             }
    220 
    221                             @Override
    222                             public void onError(){
    223                                 error(R.string.device_owner_error_wifi);
    224                             }
    225                         });
    226         }
    227 
    228         mDownloadPackageTask = new DownloadPackageTask(this,
    229                 params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum,
    230                 params.mDeviceAdminPackageDownloadCookieHeader, new DownloadPackageTask.Callback() {
    231                         @Override
    232                         public void onSuccess() {
    233                             String downloadLocation =
    234                                     mDownloadPackageTask.getDownloadedPackageLocation();
    235                             progressUpdate(R.string.progress_install);
    236                             mInstallPackageTask.run(downloadLocation);
    237                         }
    238 
    239                         @Override
    240                         public void onError(int errorCode) {
    241                             switch(errorCode) {
    242                                 case DownloadPackageTask.ERROR_HASH_MISMATCH:
    243                                     error(R.string.device_owner_error_hash_mismatch);
    244                                     break;
    245                                 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED:
    246                                     error(R.string.device_owner_error_download_failed);
    247                                     break;
    248                                 default:
    249                                     error(R.string.device_owner_error_general);
    250                                     break;
    251                             }
    252                         }
    253                     });
    254 
    255         mInstallPackageTask = new InstallPackageTask(this,
    256                 params.mDeviceAdminPackageName,
    257                 new InstallPackageTask.Callback() {
    258                     @Override
    259                     public void onSuccess() {
    260                         progressUpdate(R.string.progress_set_owner);
    261                         mSetDevicePolicyTask.run();
    262                     }
    263 
    264                     @Override
    265                     public void onError(int errorCode) {
    266                         switch(errorCode) {
    267                             case InstallPackageTask.ERROR_PACKAGE_INVALID:
    268                                 error(R.string.device_owner_error_package_invalid);
    269                                 break;
    270                             case InstallPackageTask.ERROR_INSTALLATION_FAILED:
    271                                 error(R.string.device_owner_error_installation_failed);
    272                                 break;
    273                             default:
    274                                 error(R.string.device_owner_error_general);
    275                                 break;
    276                         }
    277                     }
    278                 });
    279 
    280         mSetDevicePolicyTask = new SetDevicePolicyTask(this,
    281                 params.mDeviceAdminPackageName,
    282                 getResources().getString(R.string.default_owned_device_username),
    283                 new SetDevicePolicyTask.Callback() {
    284                     @Override
    285                     public void onSuccess() {
    286                         if (params.mLeaveAllSystemAppsEnabled) {
    287                             onProvisioningSuccess(params.mDeviceAdminPackageName);
    288                         } else {
    289                             mDeleteNonRequiredAppsTask.run();
    290                         }
    291                     }
    292 
    293                     @Override
    294                     public void onError(int errorCode) {
    295                         switch(errorCode) {
    296                             case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED:
    297                                 error(R.string.device_owner_error_package_not_installed);
    298                                 break;
    299                             case SetDevicePolicyTask.ERROR_NO_RECEIVER:
    300                                 error(R.string.device_owner_error_package_invalid);
    301                                 break;
    302                             default:
    303                                 error(R.string.device_owner_error_general);
    304                                 break;
    305                         }
    306                     }
    307                 });
    308 
    309         mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask(
    310                 this, params.mDeviceAdminPackageName, UserHandle.USER_OWNER,
    311                 R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device,
    312                 true /* We are creating a new profile */,
    313                 false /* Do not disable INSTALL_SHORTCUT listeners */,
    314                 new DeleteNonRequiredAppsTask.Callback() {
    315                     public void onSuccess() {
    316                         // Done with provisioning. Success.
    317                         onProvisioningSuccess(params.mDeviceAdminPackageName);
    318                     }
    319 
    320                     @Override
    321                     public void onError() {
    322                         error(R.string.device_owner_error_general);
    323                     };
    324                 });
    325 
    326         // Start first task, which starts next task in its callback, etc.
    327         startFirstTask(params);
    328     }
    329 
    330     private void startFirstTask(final ProvisioningParams params) {
    331         if (mAddWifiNetworkTask != null) {
    332 
    333             // Connect to wifi.
    334             progressUpdate(R.string.progress_connect_to_wifi);
    335             mAddWifiNetworkTask.run();
    336         } else if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
    337 
    338             // Download, install, set as device owner, delete apps.
    339             progressUpdate(R.string.progress_download);
    340             mDownloadPackageTask.run();
    341         } else {
    342 
    343             // Device Admin will not be downloaded (but is already present):
    344             // Just set as device owner, delete apps.
    345             progressUpdate(R.string.progress_set_owner);
    346             mSetDevicePolicyTask.run();
    347         }
    348     }
    349 
    350     private void error(int dialogMessage) {
    351         mLastErrorMessage = dialogMessage;
    352         sendError();
    353         // Wait for stopService() call from the activity.
    354     }
    355 
    356     private void sendError() {
    357         if (DEBUG) {
    358             ProvisionLogger.logd("Reporting Error: " + getResources()
    359                 .getString(mLastErrorMessage));
    360         }
    361         Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
    362         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    363         intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage);
    364         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    365     }
    366 
    367     private void progressUpdate(int progressMessage) {
    368         if (DEBUG) {
    369             ProvisionLogger.logd("Reporting progress update: " + getResources()
    370                 .getString(progressMessage));
    371         }
    372         mLastProgressMessage = progressMessage;
    373         sendProgressUpdateToActivity();
    374     }
    375 
    376     private void sendProgressUpdateToActivity() {
    377         Intent intent = new Intent(ACTION_PROGRESS_UPDATE);
    378         intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage);
    379         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    380         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    381     }
    382 
    383     private void onProvisioningSuccess(String deviceAdminPackage) {
    384         if (DEBUG) ProvisionLogger.logd("Reporting success.");
    385         mDone = true;
    386 
    387         // Enable the HomeReceiverActivity, since the DeviceOwnerProvisioningActivity will shutdown
    388         // the Setup wizard soon, which will result in a home intent that should be caught by the
    389         // HomeReceiverActivity.
    390         PackageManager pm = getPackageManager();
    391         pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this,
    392                         HomeReceiverActivity.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
    393                 PackageManager.DONT_KILL_APP);
    394 
    395         Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
    396         successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    397         LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent);
    398         // Wait for stopService() call from the activity.
    399     }
    400 
    401     private void initializeProvisioningEnvironment(ProvisioningParams params) {
    402         setTimeAndTimezone(params.mTimeZone, params.mLocalTime);
    403         setLocale(params.mLocale);
    404 
    405         // Start CDMA activation to enable phone calls.
    406         final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING);
    407         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    408         if (DEBUG) ProvisionLogger.logd("Starting cdma activation activity");
    409         startActivity(intent); // Activity will be a Nop if not a CDMA device.
    410     }
    411 
    412     private void setTimeAndTimezone(String timeZone, long localTime) {
    413         try {
    414             final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    415             if (timeZone != null) {
    416                 if (DEBUG) ProvisionLogger.logd("Setting time zone to " + timeZone);
    417                 am.setTimeZone(timeZone);
    418             }
    419             if (localTime > 0) {
    420                 if (DEBUG) ProvisionLogger.logd("Setting time to " + localTime);
    421                 am.setTime(localTime);
    422             }
    423         } catch (Exception e) {
    424             ProvisionLogger.loge("Alarm manager failed to set the system time/timezone.");
    425             // Do not stop provisioning process, but ignore this error.
    426         }
    427     }
    428 
    429     private void setLocale(Locale locale) {
    430         if (locale == null || locale.equals(Locale.getDefault())) {
    431             return;
    432         }
    433         try {
    434             if (DEBUG) ProvisionLogger.logd("Setting locale to " + locale);
    435             // If locale is different from current locale this results in a configuration change,
    436             // which will trigger the restarting of the activity.
    437             LocalePicker.updateLocale(locale);
    438         } catch (Exception e) {
    439             ProvisionLogger.loge("Failed to set the system locale.");
    440             // Do not stop provisioning process, but ignore this error.
    441         }
    442     }
    443 
    444     @Override
    445     public void onCreate () {
    446         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONCREATE.");
    447     }
    448 
    449     @Override
    450     public void onDestroy () {
    451         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONDESTROY");
    452         if (mAddWifiNetworkTask != null) {
    453             mAddWifiNetworkTask.cleanUp();
    454         }
    455         if (mDownloadPackageTask != null) {
    456             mDownloadPackageTask.cleanUp();
    457         }
    458         if (mIndirectHomeReceiver != null) {
    459             LocalBroadcastManager.getInstance(this).unregisterReceiver(mIndirectHomeReceiver);
    460             mIndirectHomeReceiver = null;
    461         }
    462 
    463     }
    464 
    465     @Override
    466     public IBinder onBind(Intent intent) {
    467         return null;
    468     }
    469 }
    470 
    471