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