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     /**
     58      * Intent action to activate the CDMA phone connection by OTASP.
     59      * This is not necessary for a GSM phone connection, which is activated automatically.
     60      * String must agree with the constants in com.android.phone.InCallScreenShowActivation.
     61      */
     62     private static final String ACTION_PERFORM_CDMA_PROVISIONING =
     63             "com.android.phone.PERFORM_CDMA_PROVISIONING";
     64 
     65     // Intent actions and extras for communication from DeviceOwnerProvisioningService to Activity.
     66     protected static final String EXTRA_PROVISIONING_PARAMS =
     67             "ProvisioningParams";
     68 
     69     // Intent actions and extras for communication from DeviceOwnerProvisioningActivity to Service.
     70     protected static final String ACTION_PROVISIONING_SUCCESS =
     71             "com.android.managedprovisioning.provisioning_success";
     72     protected static final String ACTION_PROVISIONING_ERROR =
     73             "com.android.managedprovisioning.error";
     74     protected static final String EXTRA_USER_VISIBLE_ERROR_ID_KEY =
     75             "UserVisibleErrorMessage-Id";
     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 provisioning has finished succesfully (service waiting to stop).
     98     private boolean mDone = false;
     99 
    100     // Provisioning tasks.
    101     private AddWifiNetworkTask mAddWifiNetworkTask;
    102     private DownloadPackageTask mDownloadPackageTask;
    103     private InstallPackageTask mInstallPackageTask;
    104     private SetDevicePolicyTask mSetDevicePolicyTask;
    105     private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask;
    106 
    107     private ProvisioningParams mParams;
    108 
    109     private BroadcastReceiver mIndirectHomeReceiver;
    110 
    111     @Override
    112     public int onStartCommand(final Intent intent, int flags, int startId) {
    113         ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND.");
    114 
    115         synchronized (this) { // Make operations on mProvisioningInFlight atomic.
    116             if (mProvisioningInFlight) {
    117                 ProvisionLogger.logd("Provisioning already in flight.");
    118 
    119                 sendProgressUpdateToActivity();
    120 
    121                 // Send error message if currently in error state.
    122                 if (mLastErrorMessage >= 0) {
    123                     sendError();
    124                 }
    125 
    126                 // Send success if provisioning was succesful.
    127                 if (mDone) {
    128                     onProvisioningSuccess(mParams.mDeviceAdminPackageName);
    129                 }
    130             } else {
    131                 mProvisioningInFlight = true;
    132                 ProvisionLogger.logd("First start of the service.");
    133                 progressUpdate(R.string.progress_data_process);
    134 
    135                 // Load the ProvisioningParams (from message in Intent).
    136                 mParams = (ProvisioningParams) intent.getParcelableExtra(EXTRA_PROVISIONING_PARAMS);
    137 
    138                 registerHomeIntentReceiver();
    139 
    140                 // Do the work on a separate thread.
    141                 new Thread(new Runnable() {
    142                         public void run() {
    143                             initializeProvisioningEnvironment(mParams);
    144                             startDeviceOwnerProvisioning(mParams);
    145                         }
    146                     }).start();
    147             }
    148         }
    149         return START_NOT_STICKY;
    150     }
    151 
    152     // Register the receiver for the ACTION_HOME_INDIRECT intent.
    153     // The ACTION_HOME_INDIRECT intent is used to notify this service that the home intent was send.
    154     // After receiving that intent we send the complete intent to the mdm.
    155     // Note: if we would send the complete intent earlier, the home intent can close the mdm.
    156     private void registerHomeIntentReceiver() {
    157         mIndirectHomeReceiver = new IndirectHomeReceiver();
    158         IntentFilter filter = new IntentFilter();
    159         filter.addAction(DeviceOwnerProvisioningService.ACTION_HOME_INDIRECT);
    160         LocalBroadcastManager.getInstance(this).registerReceiver(mIndirectHomeReceiver, filter);
    161     }
    162 
    163     class IndirectHomeReceiver extends BroadcastReceiver {
    164         @Override
    165         public void onReceive(Context context, Intent intent) {
    166             if (!mDone) {
    167                 return;
    168             }
    169 
    170             // Disable the HomeReceiverActivity. It's no longer of use.
    171             PackageManager pm = getPackageManager();
    172             pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this,
    173                             HomeReceiverActivity.class), PackageManager
    174                     .COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    175 
    176             // Send complete intent to mdm.
    177             Intent result = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE);
    178             result.setPackage(mParams.mDeviceAdminPackageName);
    179             result.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES |
    180                     Intent.FLAG_RECEIVER_FOREGROUND);
    181             if (mParams.mAdminExtrasBundle != null) {
    182                 result.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
    183                         mParams.mAdminExtrasBundle);
    184             }
    185             sendBroadcast(result);
    186             stopSelf();
    187         }
    188     }
    189 
    190 
    191     /**
    192      * This is the core method of this class. It goes through every provisioning step.
    193      */
    194     private void startDeviceOwnerProvisioning(final ProvisioningParams params) {
    195         ProvisionLogger.logd("Starting device owner provisioning");
    196 
    197         // Construct Tasks. Do not start them yet.
    198         mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.mWifiSsid,
    199                 params.mWifiHidden, params.mWifiSecurityType, params.mWifiPassword,
    200                 params.mWifiProxyHost, params.mWifiProxyPort, params.mWifiProxyBypassHosts,
    201                 params.mWifiPacUrl, new AddWifiNetworkTask.Callback() {
    202                         @Override
    203                         public void onSuccess() {
    204                             if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
    205                                 // Download, install, set as device owner, delete apps.
    206                                 progressUpdate(R.string.progress_download);
    207                                 mDownloadPackageTask.run();
    208                             } else {
    209                                 // Device Admin will not be downloaded (but is already present):
    210                                 // Just set as device owner, delete apps.
    211                                 progressUpdate(R.string.progress_set_owner);
    212                                 mSetDevicePolicyTask.run();
    213                             }
    214                         }
    215 
    216                         @Override
    217                         public void onError(){
    218                             error(R.string.device_owner_error_wifi);
    219                         }
    220                 });
    221 
    222         mDownloadPackageTask = new DownloadPackageTask(this,
    223                 params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum,
    224                 params.mDeviceAdminPackageDownloadCookieHeader, new DownloadPackageTask.Callback() {
    225                         @Override
    226                         public void onSuccess() {
    227                             String downloadLocation =
    228                                     mDownloadPackageTask.getDownloadedPackageLocation();
    229                             progressUpdate(R.string.progress_install);
    230                             mInstallPackageTask.run(downloadLocation);
    231                         }
    232 
    233                         @Override
    234                         public void onError(int errorCode) {
    235                             switch(errorCode) {
    236                                 case DownloadPackageTask.ERROR_HASH_MISMATCH:
    237                                     error(R.string.device_owner_error_hash_mismatch);
    238                                     break;
    239                                 case DownloadPackageTask.ERROR_DOWNLOAD_FAILED:
    240                                     error(R.string.device_owner_error_download_failed);
    241                                     break;
    242                                 default:
    243                                     error(R.string.device_owner_error_general);
    244                                     break;
    245                             }
    246                         }
    247                     });
    248 
    249         mInstallPackageTask = new InstallPackageTask(this,
    250                 params.mDeviceAdminPackageName,
    251                 new InstallPackageTask.Callback() {
    252                     @Override
    253                     public void onSuccess() {
    254                         progressUpdate(R.string.progress_set_owner);
    255                         mSetDevicePolicyTask.run();
    256                     }
    257 
    258                     @Override
    259                     public void onError(int errorCode) {
    260                         switch(errorCode) {
    261                             case InstallPackageTask.ERROR_PACKAGE_INVALID:
    262                                 error(R.string.device_owner_error_package_invalid);
    263                                 break;
    264                             case InstallPackageTask.ERROR_INSTALLATION_FAILED:
    265                                 error(R.string.device_owner_error_installation_failed);
    266                                 break;
    267                             default:
    268                                 error(R.string.device_owner_error_general);
    269                                 break;
    270                         }
    271                     }
    272                 });
    273 
    274         mSetDevicePolicyTask = new SetDevicePolicyTask(this,
    275                 params.mDeviceAdminPackageName,
    276                 getResources().getString(R.string.default_owned_device_username),
    277                 new SetDevicePolicyTask.Callback() {
    278                     @Override
    279                     public void onSuccess() {
    280                         mDeleteNonRequiredAppsTask.run();
    281                     }
    282 
    283                     @Override
    284                     public void onError(int errorCode) {
    285                         switch(errorCode) {
    286                             case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED:
    287                                 error(R.string.device_owner_error_package_not_installed);
    288                                 break;
    289                             case SetDevicePolicyTask.ERROR_NO_RECEIVER:
    290                                 error(R.string.device_owner_error_package_invalid);
    291                                 break;
    292                             default:
    293                                 error(R.string.device_owner_error_general);
    294                                 break;
    295                         }
    296                     }
    297                 });
    298 
    299         mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask(
    300                 this, params.mDeviceAdminPackageName, UserHandle.USER_OWNER,
    301                 R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device,
    302                 true /* We are creating a new profile */,
    303                 false /* Do not disable INSTALL_SHORTCUT listeners */,
    304                 new DeleteNonRequiredAppsTask.Callback() {
    305                     public void onSuccess() {
    306                         // Done with provisioning. Success.
    307                         onProvisioningSuccess(params.mDeviceAdminPackageName);
    308                     }
    309 
    310                     @Override
    311                     public void onError() {
    312                         error(R.string.device_owner_error_general);
    313                     };
    314                 });
    315 
    316         // Start first task, which starts next task in its callback, etc.
    317         startFirstTask(params);
    318     }
    319 
    320     private void startFirstTask(final ProvisioningParams params) {
    321         if (!TextUtils.isEmpty(params.mWifiSsid)) {
    322 
    323             // Connect to wifi.
    324             progressUpdate(R.string.progress_connect_to_wifi);
    325             mAddWifiNetworkTask.run();
    326         } else if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
    327 
    328             // Download, install, set as device owner, delete apps.
    329             progressUpdate(R.string.progress_download);
    330             mDownloadPackageTask.run();
    331         } else {
    332 
    333             // Device Admin will not be downloaded (but is already present):
    334             // Just set as device owner, delete apps.
    335             progressUpdate(R.string.progress_set_owner);
    336             mSetDevicePolicyTask.run();
    337         }
    338     }
    339 
    340     private void error(int dialogMessage) {
    341         mLastErrorMessage = dialogMessage;
    342         sendError();
    343         // Wait for stopService() call from the activity.
    344     }
    345 
    346     private void sendError() {
    347         ProvisionLogger.logd("Reporting Error: " + getResources().getString(mLastErrorMessage));
    348         Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
    349         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    350         intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage);
    351         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    352     }
    353 
    354     private void progressUpdate(int progressMessage) {
    355         ProvisionLogger.logd("Reporting progress update: "
    356                 + getResources().getString(progressMessage));
    357         mLastProgressMessage = progressMessage;
    358         sendProgressUpdateToActivity();
    359     }
    360 
    361     private void sendProgressUpdateToActivity() {
    362         Intent intent = new Intent(ACTION_PROGRESS_UPDATE);
    363         intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage);
    364         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    365         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    366     }
    367 
    368     private void onProvisioningSuccess(String deviceAdminPackage) {
    369         ProvisionLogger.logv("Reporting success.");
    370         mDone = true;
    371 
    372         // Enable the HomeReceiverActivity, since the DeviceOwnerProvisioningActivity will shutdown
    373         // the Setup wizard soon, which will result in a home intent that should be caught by the
    374         // HomeReceiverActivity.
    375         PackageManager pm = getPackageManager();
    376         pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this,
    377                         HomeReceiverActivity.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
    378                 PackageManager.DONT_KILL_APP);
    379 
    380         Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
    381         successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
    382         LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent);
    383         // Wait for stopService() call from the activity.
    384     }
    385 
    386     private void initializeProvisioningEnvironment(ProvisioningParams params) {
    387         setTimeAndTimezone(params.mTimeZone, params.mLocalTime);
    388         setLocale(params.mLocale);
    389 
    390         // Start CDMA activation to enable phone calls.
    391         final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING);
    392         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    393         ProvisionLogger.logv("Starting cdma activation activity");
    394         startActivity(intent); // Activity will be a Nop if not a CDMA device.
    395     }
    396 
    397     private void setTimeAndTimezone(String timeZone, long localTime) {
    398         try {
    399             final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    400             if (timeZone != null) {
    401                 ProvisionLogger.logd("Setting time zone to " + timeZone);
    402                 am.setTimeZone(timeZone);
    403             }
    404             if (localTime > 0) {
    405                 ProvisionLogger.logd("Setting time to " + localTime);
    406                 am.setTime(localTime);
    407             }
    408         } catch (Exception e) {
    409             ProvisionLogger.loge("Alarm manager failed to set the system time/timezone.");
    410             // Do not stop provisioning process, but ignore this error.
    411         }
    412     }
    413 
    414     private void setLocale(Locale locale) {
    415         if (locale == null || locale.equals(Locale.getDefault())) {
    416             return;
    417         }
    418         try {
    419             ProvisionLogger.logd("Setting locale to " + locale);
    420             // If locale is different from current locale this results in a configuration change,
    421             // which will trigger the restarting of the activity.
    422             LocalePicker.updateLocale(locale);
    423         } catch (Exception e) {
    424             ProvisionLogger.loge("Failed to set the system locale.");
    425             // Do not stop provisioning process, but ignore this error.
    426         }
    427     }
    428 
    429     @Override
    430     public void onCreate () {
    431         ProvisionLogger.logd("Device owner provisioning service ONCREATE.");
    432     }
    433 
    434     @Override
    435     public void onDestroy () {
    436         ProvisionLogger.logd("Device owner provisioning service ONDESTROY");
    437         if (mAddWifiNetworkTask != null) {
    438             mAddWifiNetworkTask.cleanUp();
    439         }
    440         if (mDownloadPackageTask != null) {
    441             mDownloadPackageTask.cleanUp();
    442         }
    443         if (mIndirectHomeReceiver != null) {
    444             LocalBroadcastManager.getInstance(this).unregisterReceiver(mIndirectHomeReceiver);
    445             mIndirectHomeReceiver = null;
    446         }
    447 
    448     }
    449 
    450     @Override
    451     public IBinder onBind(Intent intent) {
    452         return null;
    453     }
    454 }
    455 
    456