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