DeviceOwnerProvisioningService.java revision 326bcfdd72218a2d3b35d8e1ca80b8e36263402e
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                            progressUpdate(R.string.progress_download);
150                            mDownloadPackageTask.run();
151                        }
152
153                        @Override
154                        public void onError(){
155                            error(R.string.device_owner_error_wifi);
156                        }
157                });
158
159        mDownloadPackageTask = new DownloadPackageTask(this,
160                params.mDeviceAdminPackageDownloadLocation, params.mDeviceAdminPackageChecksum,
161                new DownloadPackageTask.Callback() {
162                        @Override
163                        public void onSuccess() {
164                            String downloadLocation =
165                                    mDownloadPackageTask.getDownloadedPackageLocation();
166                            progressUpdate(R.string.progress_install);
167                            mInstallPackageTask.run(downloadLocation);
168                        }
169
170                        @Override
171                        public void onError(int errorCode) {
172                            switch(errorCode) {
173                                case DownloadPackageTask.ERROR_HASH_MISMATCH:
174                                    error(R.string.device_owner_error_hash_mismatch);
175                                    break;
176                                case DownloadPackageTask.ERROR_DOWNLOAD_FAILED:
177                                    error(R.string.device_owner_error_download_failed);
178                                    break;
179                                default:
180                                    error(R.string.device_owner_error_general);
181                                    break;
182                            }
183                        }
184                    });
185
186        mInstallPackageTask = new InstallPackageTask(this,
187                params.mDeviceAdminPackageName,
188                new InstallPackageTask.Callback() {
189                    @Override
190                    public void onSuccess() {
191                        progressUpdate(R.string.progress_set_owner);
192                        mSetDevicePolicyTask.run();
193                    }
194
195                    @Override
196                    public void onError(int errorCode) {
197                        switch(errorCode) {
198                            case InstallPackageTask.ERROR_PACKAGE_INVALID:
199                                error(R.string.device_owner_error_package_invalid);
200                                break;
201                            case InstallPackageTask.ERROR_INSTALLATION_FAILED:
202                                error(R.string.device_owner_error_installation_failed);
203                                break;
204                            default:
205                                error(R.string.device_owner_error_general);
206                                break;
207                        }
208                    }
209                });
210
211        mSetDevicePolicyTask = new SetDevicePolicyTask(this,
212                params.mDeviceAdminPackageName,
213                getResources().getString(R.string.default_owned_device_username),
214                new SetDevicePolicyTask.Callback() {
215                    @Override
216                    public void onSuccess() {
217                        mDeleteNonRequiredAppsTask.run();
218                    }
219
220                    @Override
221                    public void onError(int errorCode) {
222                        switch(errorCode) {
223                            case SetDevicePolicyTask.ERROR_PACKAGE_NOT_INSTALLED:
224                                error(R.string.device_owner_error_package_not_installed);
225                                break;
226                            case SetDevicePolicyTask.ERROR_NO_RECEIVER:
227                                error(R.string.device_owner_error_missing_receiver);
228                                break;
229                            default:
230                                error(R.string.device_owner_error_general);
231                                break;
232                        }
233                    }
234                });
235
236        mDeleteNonRequiredAppsTask =  new DeleteNonRequiredAppsTask(
237                this, params.mDeviceAdminPackageName, 0 /* primary user's UserId */,
238                R.array.required_apps_managed_device, R.array.vendor_required_apps_managed_device,
239                new DeleteNonRequiredAppsTask.Callback() {
240                    public void onSuccess() {
241                        // Done with provisioning. Success.
242                        onProvisioningSuccess(params.mDeviceAdminPackageName);
243                    }
244
245                    @Override
246                    public void onError() {
247                        error(R.string.device_owner_error_general);
248                    };
249                });
250
251        // Start first task, which starts next task in its callback, etc.
252        if (!TextUtils.isEmpty(params.mDeviceAdminPackageDownloadLocation)) {
253            // Device Admin has to be downloaded:
254            // Connect to wifi, download, install, set as device owner, delete apps.
255            progressUpdate(R.string.progress_connect_to_wifi);
256            mAddWifiNetworkTask.run();
257        } else {
258            // Device Admin will not be downloaded (but is already present):
259            // Just set as device owner, delete apps.
260            progressUpdate(R.string.progress_set_owner);
261            mSetDevicePolicyTask.run();
262        }
263    }
264
265    private void error(int dialogMessage) {
266        mLastErrorMessage = dialogMessage;
267        sendError();
268        // Wait for stopService() call from the activity.
269    }
270
271    private void sendError() {
272        ProvisionLogger.logd("Reporting Error: " + getResources().getString(mLastErrorMessage));
273        Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
274        intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
275        intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage);
276        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
277    }
278
279    private void progressUpdate(int progressMessage) {
280        ProvisionLogger.logd("Reporting progress update: "
281                + getResources().getString(progressMessage));
282        mLastProgressMessage = progressMessage;
283        sendProgressUpdateToActivity();
284    }
285
286    private void sendProgressUpdateToActivity() {
287        Intent intent = new Intent(ACTION_PROGRESS_UPDATE);
288        intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage);
289        intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
290        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
291    }
292
293    private void onProvisioningSuccess(String deviceAdminPackage) {
294        ProvisionLogger.logv("Reporting success.");
295        mDone = true;
296        Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
297        successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
298        LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent);
299        // Wait for stopService() call from the activity.
300    }
301
302    private void initializeProvisioningEnvironment(ProvisioningParams params) {
303        setTimeAndTimezone(params.mTimeZone, params.mLocalTime);
304        setLocale(params.mLocale);
305
306        // Start CDMA activation to enable phone calls.
307        final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING);
308        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
309        ProvisionLogger.logv("Starting cdma activation activity");
310        startActivity(intent); // Activity will be a Nop if not a CDMA device.
311    }
312
313    private void setTimeAndTimezone(String timeZone, long localTime) {
314        try {
315            final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
316            if (timeZone != null) {
317                ProvisionLogger.logd("Setting time zone to " + timeZone);
318                am.setTimeZone(timeZone);
319            }
320            if (localTime > 0) {
321                ProvisionLogger.logd("Setting time to " + localTime);
322                am.setTime(localTime);
323            }
324        } catch (Exception e) {
325            ProvisionLogger.loge("Alarm manager failed to set the system time/timezone.");
326            // Do not stop provisioning process, but ignore this error.
327        }
328    }
329
330    private void setLocale(Locale locale) {
331        if (locale == null || locale.equals(Locale.getDefault())) {
332            return;
333        }
334        try {
335            ProvisionLogger.logd("Setting locale to " + locale);
336            // If locale is different from current locale this results in a configuration change,
337            // which will trigger the restarting of the activity.
338            LocalePicker.updateLocale(locale);
339        } catch (Exception e) {
340            ProvisionLogger.loge("Failed to set the system locale.");
341            // Do not stop provisioning process, but ignore this error.
342        }
343    }
344
345    @Override
346    public void onCreate () {
347        ProvisionLogger.logd("Device owner provisioning service ONCREATE.");
348    }
349
350    @Override
351    public void onDestroy () {
352        ProvisionLogger.logd("Device owner provisioning service ONDESTROY");
353        if (mAddWifiNetworkTask != null) {
354            mAddWifiNetworkTask.cleanUp();
355        }
356        if (mDownloadPackageTask != null) {
357            mDownloadPackageTask.cleanUp();
358        }
359    }
360
361    @Override
362    public IBinder onBind(Intent intent) {
363        return null;
364    }
365}
366
367