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