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