DeviceOwnerProvisioningService.java revision fd134872830d02440e91ea99605fe10928dedc03
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
17package com.android.managedprovisioning;
18
19import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
20import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
21
22import android.app.AlarmManager;
23import android.app.Service;
24import android.content.BroadcastReceiver;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.PackageManager;
30import android.os.Bundle;
31import android.os.IBinder;
32import android.os.UserHandle;
33import android.support.v4.content.LocalBroadcastManager;
34import android.text.TextUtils;
35
36import com.android.internal.app.LocalePicker;
37import com.android.managedprovisioning.task.AddWifiNetworkTask;
38import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask;
39import com.android.managedprovisioning.task.DownloadPackageTask;
40import com.android.managedprovisioning.task.InstallPackageTask;
41import com.android.managedprovisioning.task.SetDevicePolicyTask;
42
43import java.lang.Runnable;
44import 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 */
56public 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        mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.mWifiSsid,
201                params.mWifiHidden, params.mWifiSecurityType, params.mWifiPassword,
202                params.mWifiProxyHost, params.mWifiProxyPort, params.mWifiProxyBypassHosts,
203                params.mWifiPacUrl, new AddWifiNetworkTask.Callback() {
204                        @Override
205                        public void onSuccess() {
206                            if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
207                                // Download, install, set as device owner, delete apps.
208                                progressUpdate(R.string.progress_download);
209                                mDownloadPackageTask.run();
210                            } else {
211                                // Device Admin will not be downloaded (but is already present):
212                                // Just set as device owner, delete apps.
213                                progressUpdate(R.string.progress_set_owner);
214                                mSetDevicePolicyTask.run();
215                            }
216                        }
217
218                        @Override
219                        public void onError(){
220                            error(R.string.device_owner_error_wifi);
221                        }
222                });
223
224        mDownloadPackageTask = new DownloadPackageTask(this,
225                params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum,
226                params.mDeviceAdminPackageDownloadCookieHeader, new DownloadPackageTask.Callback() {
227                        @Override
228                        public void onSuccess() {
229                            String downloadLocation =
230                                    mDownloadPackageTask.getDownloadedPackageLocation();
231                            progressUpdate(R.string.progress_install);
232                            mInstallPackageTask.run(downloadLocation);
233                        }
234
235                        @Override
236                        public void onError(int errorCode) {
237                            switch(errorCode) {
238                                case DownloadPackageTask.ERROR_HASH_MISMATCH:
239                                    error(R.string.device_owner_error_hash_mismatch);
240                                    break;
241                                case DownloadPackageTask.ERROR_DOWNLOAD_FAILED:
242                                    error(R.string.device_owner_error_download_failed);
243                                    break;
244                                default:
245                                    error(R.string.device_owner_error_general);
246                                    break;
247                            }
248                        }
249                    });
250
251        mInstallPackageTask = new InstallPackageTask(this,
252                params.mDeviceAdminPackageName,
253                new InstallPackageTask.Callback() {
254                    @Override
255                    public void onSuccess() {
256                        progressUpdate(R.string.progress_set_owner);
257                        mSetDevicePolicyTask.run();
258                    }
259
260                    @Override
261                    public void onError(int errorCode) {
262                        switch(errorCode) {
263                            case InstallPackageTask.ERROR_PACKAGE_INVALID:
264                                error(R.string.device_owner_error_package_invalid);
265                                break;
266                            case InstallPackageTask.ERROR_INSTALLATION_FAILED:
267                                error(R.string.device_owner_error_installation_failed);
268                                break;
269                            default:
270                                error(R.string.device_owner_error_general);
271                                break;
272                        }
273                    }
274                });
275
276        mSetDevicePolicyTask = new SetDevicePolicyTask(this,
277                params.mDeviceAdminPackageName,
278                getResources().getString(R.string.default_owned_device_username),
279                new SetDevicePolicyTask.Callback() {
280                    @Override
281                    public void onSuccess() {
282                        if (params.mLeaveAllSystemAppsEnabled) {
283                            onProvisioningSuccess(params.mDeviceAdminPackageName);
284                        } else {
285                            mDeleteNonRequiredAppsTask.run();
286                        }
287                    }
288
289                    @Override
290                    public void onError(int errorCode) {
291                        switch(errorCode) {
292                            case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED:
293                                error(R.string.device_owner_error_package_not_installed);
294                                break;
295                            case SetDevicePolicyTask.ERROR_NO_RECEIVER:
296                                error(R.string.device_owner_error_package_invalid);
297                                break;
298                            default:
299                                error(R.string.device_owner_error_general);
300                                break;
301                        }
302                    }
303                });
304
305        mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask(
306                this, params.mDeviceAdminPackageName, UserHandle.USER_OWNER,
307                R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device,
308                true /* We are creating a new profile */,
309                false /* Do not disable INSTALL_SHORTCUT listeners */,
310                new DeleteNonRequiredAppsTask.Callback() {
311                    public void onSuccess() {
312                        // Done with provisioning. Success.
313                        onProvisioningSuccess(params.mDeviceAdminPackageName);
314                    }
315
316                    @Override
317                    public void onError() {
318                        error(R.string.device_owner_error_general);
319                    };
320                });
321
322        // Start first task, which starts next task in its callback, etc.
323        startFirstTask(params);
324    }
325
326    private void startFirstTask(final ProvisioningParams params) {
327        if (!TextUtils.isEmpty(params.mWifiSsid)) {
328
329            // Connect to wifi.
330            progressUpdate(R.string.progress_connect_to_wifi);
331            mAddWifiNetworkTask.run();
332        } else if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
333
334            // Download, install, set as device owner, delete apps.
335            progressUpdate(R.string.progress_download);
336            mDownloadPackageTask.run();
337        } else {
338
339            // Device Admin will not be downloaded (but is already present):
340            // Just set as device owner, delete apps.
341            progressUpdate(R.string.progress_set_owner);
342            mSetDevicePolicyTask.run();
343        }
344    }
345
346    private void error(int dialogMessage) {
347        mLastErrorMessage = dialogMessage;
348        sendError();
349        // Wait for stopService() call from the activity.
350    }
351
352    private void sendError() {
353        if (DEBUG) {
354            ProvisionLogger.logd("Reporting Error: " + getResources()
355                .getString(mLastErrorMessage));
356        }
357        Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
358        intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
359        intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage);
360        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
361    }
362
363    private void progressUpdate(int progressMessage) {
364        if (DEBUG) {
365            ProvisionLogger.logd("Reporting progress update: " + getResources()
366                .getString(progressMessage));
367        }
368        mLastProgressMessage = progressMessage;
369        sendProgressUpdateToActivity();
370    }
371
372    private void sendProgressUpdateToActivity() {
373        Intent intent = new Intent(ACTION_PROGRESS_UPDATE);
374        intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage);
375        intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
376        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
377    }
378
379    private void onProvisioningSuccess(String deviceAdminPackage) {
380        if (DEBUG) ProvisionLogger.logd("Reporting success.");
381        mDone = true;
382
383        // Enable the HomeReceiverActivity, since the DeviceOwnerProvisioningActivity will shutdown
384        // the Setup wizard soon, which will result in a home intent that should be caught by the
385        // HomeReceiverActivity.
386        PackageManager pm = getPackageManager();
387        pm.setComponentEnabledSetting(new ComponentName(DeviceOwnerProvisioningService.this,
388                        HomeReceiverActivity.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
389                PackageManager.DONT_KILL_APP);
390
391        Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
392        successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
393        LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent);
394        // Wait for stopService() call from the activity.
395    }
396
397    private void initializeProvisioningEnvironment(ProvisioningParams params) {
398        setTimeAndTimezone(params.mTimeZone, params.mLocalTime);
399        setLocale(params.mLocale);
400
401        // Start CDMA activation to enable phone calls.
402        final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING);
403        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
404        if (DEBUG) ProvisionLogger.logd("Starting cdma activation activity");
405        startActivity(intent); // Activity will be a Nop if not a CDMA device.
406    }
407
408    private void setTimeAndTimezone(String timeZone, long localTime) {
409        try {
410            final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
411            if (timeZone != null) {
412                if (DEBUG) ProvisionLogger.logd("Setting time zone to " + timeZone);
413                am.setTimeZone(timeZone);
414            }
415            if (localTime > 0) {
416                if (DEBUG) ProvisionLogger.logd("Setting time to " + localTime);
417                am.setTime(localTime);
418            }
419        } catch (Exception e) {
420            ProvisionLogger.loge("Alarm manager failed to set the system time/timezone.");
421            // Do not stop provisioning process, but ignore this error.
422        }
423    }
424
425    private void setLocale(Locale locale) {
426        if (locale == null || locale.equals(Locale.getDefault())) {
427            return;
428        }
429        try {
430            if (DEBUG) ProvisionLogger.logd("Setting locale to " + locale);
431            // If locale is different from current locale this results in a configuration change,
432            // which will trigger the restarting of the activity.
433            LocalePicker.updateLocale(locale);
434        } catch (Exception e) {
435            ProvisionLogger.loge("Failed to set the system locale.");
436            // Do not stop provisioning process, but ignore this error.
437        }
438    }
439
440    @Override
441    public void onCreate () {
442        if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONCREATE.");
443    }
444
445    @Override
446    public void onDestroy () {
447        if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONDESTROY");
448        if (mAddWifiNetworkTask != null) {
449            mAddWifiNetworkTask.cleanUp();
450        }
451        if (mDownloadPackageTask != null) {
452            mDownloadPackageTask.cleanUp();
453        }
454        if (mIndirectHomeReceiver != null) {
455            LocalBroadcastManager.getInstance(this).unregisterReceiver(mIndirectHomeReceiver);
456            mIndirectHomeReceiver = null;
457        }
458
459    }
460
461    @Override
462    public IBinder onBind(Intent intent) {
463        return null;
464    }
465}
466
467