DeviceOwnerProvisioningService.java revision e3866c7c1cc0feb307bb9822a313181aed7394be
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 android.app.AlarmManager;
20import android.app.Service;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.os.Bundle;
25import android.os.IBinder;
26import android.support.v4.content.LocalBroadcastManager;
27import android.text.TextUtils;
28
29import com.android.internal.app.LocalePicker;
30import com.android.managedprovisioning.task.AddWifiNetworkTask;
31import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask;
32import com.android.managedprovisioning.task.DownloadPackageTask;
33import com.android.managedprovisioning.task.InstallPackageTask;
34import com.android.managedprovisioning.task.SetDevicePolicyTask;
35
36import java.lang.Runnable;
37import java.util.Locale;
38
39/**
40 * This service does the work for the DeviceOwnerProvisioningActivity.
41 * Feedback is sent back to the activity via intents.
42 *
43 * <p>
44 * If the corresponding activity is killed and restarted, the service is
45 * called twice. The service will not start the provisioning flow a second time, but instead
46 * send a status update to the activity.
47 * </p>
48 */
49public class DeviceOwnerProvisioningService extends Service {
50    /**
51     * Intent action to activate the CDMA phone connection by OTASP.
52     * This is not necessary for a GSM phone connection, which is activated automatically.
53     * String must agree with the constants in com.android.phone.InCallScreenShowActivation.
54     */
55    private static final String ACTION_PERFORM_CDMA_PROVISIONING =
56            "com.android.phone.PERFORM_CDMA_PROVISIONING";
57
58    // Intent actions and extras for communication from DeviceOwnerProvisioningService to Activity.
59    protected static final String EXTRA_PROVISIONING_PARAMS =
60            "ProvisioningParams";
61
62    // Intent actions and extras for communication from DeviceOwnerProvisioningActivity to Service.
63    protected static final String ACTION_PROVISIONING_SUCCESS =
64            "com.android.managedprovisioning.provisioning_success";
65    protected static final String ACTION_PROVISIONING_ERROR =
66            "com.android.managedprovisioning.error";
67    protected static final String EXTRA_USER_VISIBLE_ERROR_ID_KEY =
68            "UserVisibleErrorMessage-Id";
69    protected static final String ACTION_PROGRESS_UPDATE =
70            "com.android.managedprovisioning.progress_update";
71    protected static final String EXTRA_PROGRESS_MESSAGE_ID_KEY =
72            "ProgressMessageId";
73    protected static final String ACTION_REQUEST_WIFI_PICK =
74            "com.android.managedprovisioning.request_wifi_pick";
75
76    // Indicates whether provisioning has started.
77    private boolean mProvisioningInFlight = false;
78
79    // MessageId of the last progress message.
80    private int mLastProgressMessage = -1;
81
82    // MessageId of the last error message.
83    private int mLastErrorMessage = -1;
84
85    // Indicates whether provisioning has finished succesfully (service waiting to stop).
86    private boolean mDone = false;
87
88    // Provisioning tasks.
89    private AddWifiNetworkTask mAddWifiNetworkTask;
90    private DownloadPackageTask mDownloadPackageTask;
91    private InstallPackageTask mInstallPackageTask;
92    private SetDevicePolicyTask mSetDevicePolicyTask;
93    private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask;
94
95    private ProvisioningParams mParams;
96
97    @Override
98    public int onStartCommand(final Intent intent, int flags, int startId) {
99        ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND.");
100
101        synchronized (this) { // Make operations on mProvisioningInFlight atomic.
102            if (mProvisioningInFlight) {
103                ProvisionLogger.logd("Provisioning already in flight.");
104
105                sendProgressUpdateToActivity();
106
107                // Send error message if currently in error state.
108                if (mLastErrorMessage >= 0) {
109                    sendError();
110                }
111
112                // Send success if provisioning was succesful.
113                if (mDone) {
114                    onProvisioningSuccess(mParams.mDeviceAdminPackageName);
115                }
116            } else {
117                mProvisioningInFlight = true;
118                ProvisionLogger.logd("First start of the service.");
119                progressUpdate(R.string.progress_data_process);
120
121                // Load the ProvisioningParams (from message in Intent).
122                mParams = (ProvisioningParams) intent.getParcelableExtra(EXTRA_PROVISIONING_PARAMS);
123
124                // Do the work on a separate thread.
125                new Thread(new Runnable() {
126                        public void run() {
127                            initializeProvisioningEnvironment(mParams);
128                            startDeviceOwnerProvisioning(mParams);
129                        }
130                    }).start();
131            }
132        }
133        return START_NOT_STICKY;
134    }
135
136    /**
137     * This is the core method of this class. It goes through every provisioning step.
138     */
139    private void startDeviceOwnerProvisioning(final ProvisioningParams params) {
140        ProvisionLogger.logd("Starting device owner provisioning");
141
142        // Construct Tasks. Do not start them yet.
143        mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.mWifiSsid,
144                params.mWifiHidden, params.mWifiSecurityType, params.mWifiPassword,
145                params.mWifiProxyHost, params.mWifiProxyPort, params.mWifiProxyBypassHosts,
146                params.mWifiPacUrl, new AddWifiNetworkTask.Callback() {
147                        @Override
148                        public void onSuccess() {
149                            if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
150                                // Download, install, set as device owner, delete apps.
151                                progressUpdate(R.string.progress_download);
152                                mDownloadPackageTask.run();
153                            } else {
154                                // Device Admin will not be downloaded (but is already present):
155                                // Just set as device owner, delete apps.
156                                progressUpdate(R.string.progress_set_owner);
157                                mSetDevicePolicyTask.run();
158                            }
159                        }
160
161                        @Override
162                        public void onError(){
163                            error(R.string.device_owner_error_wifi);
164                        }
165                });
166
167        mDownloadPackageTask = new DownloadPackageTask(this,
168                params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum,
169                params.mDeviceAdminPackageDownloadCookieHeader, new DownloadPackageTask.Callback() {
170                        @Override
171                        public void onSuccess() {
172                            String downloadLocation =
173                                    mDownloadPackageTask.getDownloadedPackageLocation();
174                            progressUpdate(R.string.progress_install);
175                            mInstallPackageTask.run(downloadLocation);
176                        }
177
178                        @Override
179                        public void onError(int errorCode) {
180                            switch(errorCode) {
181                                case DownloadPackageTask.ERROR_HASH_MISMATCH:
182                                    error(R.string.device_owner_error_hash_mismatch);
183                                    break;
184                                case DownloadPackageTask.ERROR_DOWNLOAD_FAILED:
185                                    error(R.string.device_owner_error_download_failed);
186                                    break;
187                                default:
188                                    error(R.string.device_owner_error_general);
189                                    break;
190                            }
191                        }
192                    });
193
194        mInstallPackageTask = new InstallPackageTask(this,
195                params.mDeviceAdminPackageName,
196                new InstallPackageTask.Callback() {
197                    @Override
198                    public void onSuccess() {
199                        progressUpdate(R.string.progress_set_owner);
200                        mSetDevicePolicyTask.run();
201                    }
202
203                    @Override
204                    public void onError(int errorCode) {
205                        switch(errorCode) {
206                            case InstallPackageTask.ERROR_PACKAGE_INVALID:
207                                error(R.string.device_owner_error_package_invalid);
208                                break;
209                            case InstallPackageTask.ERROR_INSTALLATION_FAILED:
210                                error(R.string.device_owner_error_installation_failed);
211                                break;
212                            default:
213                                error(R.string.device_owner_error_general);
214                                break;
215                        }
216                    }
217                });
218
219        mSetDevicePolicyTask = new SetDevicePolicyTask(this,
220                params.mDeviceAdminPackageName,
221                getResources().getString(R.string.default_owned_device_username),
222                new SetDevicePolicyTask.Callback() {
223                    @Override
224                    public void onSuccess() {
225                        mDeleteNonRequiredAppsTask.run();
226                    }
227
228                    @Override
229                    public void onError(int errorCode) {
230                        switch(errorCode) {
231                            case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED:
232                                error(R.string.device_owner_error_package_not_installed);
233                                break;
234                            case SetDevicePolicyTask.ERROR_NO_RECEIVER:
235                                error(R.string.device_owner_error_package_invalid);
236                                break;
237                            default:
238                                error(R.string.device_owner_error_general);
239                                break;
240                        }
241                    }
242                });
243
244        mDeleteNonRequiredAppsTask =  new DeleteNonRequiredAppsTask(
245                this, params.mDeviceAdminPackageName, 0 /* primary user's UserId */,
246                R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device,
247                new DeleteNonRequiredAppsTask.Callback() {
248                    public void onSuccess() {
249                        // Done with provisioning. Success.
250                        onProvisioningSuccess(params.mDeviceAdminPackageName);
251                    }
252
253                    @Override
254                    public void onError() {
255                        error(R.string.device_owner_error_general);
256                    };
257                });
258
259        // Start first task, which starts next task in its callback, etc.
260        startFirstTask(params);
261    }
262
263    private void startFirstTask(final ProvisioningParams params) {
264        if (!TextUtils.isEmpty(params.mWifiSsid)) {
265
266            // Connect to wifi.
267            progressUpdate(R.string.progress_connect_to_wifi);
268            mAddWifiNetworkTask.run();
269        } else if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
270
271            // Download, install, set as device owner, delete apps.
272            progressUpdate(R.string.progress_download);
273            mDownloadPackageTask.run();
274        } else {
275
276            // Device Admin will not be downloaded (but is already present):
277            // Just set as device owner, delete apps.
278            progressUpdate(R.string.progress_set_owner);
279            mSetDevicePolicyTask.run();
280        }
281    }
282
283    private void error(int dialogMessage) {
284        mLastErrorMessage = dialogMessage;
285        sendError();
286        // Wait for stopService() call from the activity.
287    }
288
289    private void sendError() {
290        ProvisionLogger.logd("Reporting Error: " + getResources().getString(mLastErrorMessage));
291        Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
292        intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
293        intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage);
294        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
295    }
296
297    private void progressUpdate(int progressMessage) {
298        ProvisionLogger.logd("Reporting progress update: "
299                + getResources().getString(progressMessage));
300        mLastProgressMessage = progressMessage;
301        sendProgressUpdateToActivity();
302    }
303
304    private void sendProgressUpdateToActivity() {
305        Intent intent = new Intent(ACTION_PROGRESS_UPDATE);
306        intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage);
307        intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
308        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
309    }
310
311    private void onProvisioningSuccess(String deviceAdminPackage) {
312        ProvisionLogger.logv("Reporting success.");
313        mDone = true;
314        Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
315        successIntent.putExtra(EXTRA_PROVISIONING_PARAMS, mParams);
316        successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
317        LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent);
318        // Wait for stopService() call from the activity.
319    }
320
321    private void initializeProvisioningEnvironment(ProvisioningParams params) {
322        setTimeAndTimezone(params.mTimeZone, params.mLocalTime);
323        setLocale(params.mLocale);
324
325        // Start CDMA activation to enable phone calls.
326        final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING);
327        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
328        ProvisionLogger.logv("Starting cdma activation activity");
329        startActivity(intent); // Activity will be a Nop if not a CDMA device.
330    }
331
332    private void setTimeAndTimezone(String timeZone, long localTime) {
333        try {
334            final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
335            if (timeZone != null) {
336                ProvisionLogger.logd("Setting time zone to " + timeZone);
337                am.setTimeZone(timeZone);
338            }
339            if (localTime > 0) {
340                ProvisionLogger.logd("Setting time to " + localTime);
341                am.setTime(localTime);
342            }
343        } catch (Exception e) {
344            ProvisionLogger.loge("Alarm manager failed to set the system time/timezone.");
345            // Do not stop provisioning process, but ignore this error.
346        }
347    }
348
349    private void setLocale(Locale locale) {
350        if (locale == null || locale.equals(Locale.getDefault())) {
351            return;
352        }
353        try {
354            ProvisionLogger.logd("Setting locale to " + locale);
355            // If locale is different from current locale this results in a configuration change,
356            // which will trigger the restarting of the activity.
357            LocalePicker.updateLocale(locale);
358        } catch (Exception e) {
359            ProvisionLogger.loge("Failed to set the system locale.");
360            // Do not stop provisioning process, but ignore this error.
361        }
362    }
363
364    @Override
365    public void onCreate () {
366        ProvisionLogger.logd("Device owner provisioning service ONCREATE.");
367    }
368
369    @Override
370    public void onDestroy () {
371        ProvisionLogger.logd("Device owner provisioning service ONDESTROY");
372        if (mAddWifiNetworkTask != null) {
373            mAddWifiNetworkTask.cleanUp();
374        }
375        if (mDownloadPackageTask != null) {
376            mDownloadPackageTask.cleanUp();
377        }
378    }
379
380    @Override
381    public IBinder onBind(Intent intent) {
382        return null;
383    }
384}
385
386