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 
17 package com.android.managedprovisioning;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE;
20 
21 import android.app.AlarmManager;
22 import android.app.Service;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.PackageManager;
28 import android.os.Bundle;
29 import android.os.IBinder;
30 import android.os.Process;
31 import android.os.UserHandle;
32 import android.os.UserManager;
33 import android.support.v4.content.LocalBroadcastManager;
34 
35 import com.android.internal.app.LocalePicker;
36 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
37 import com.android.managedprovisioning.common.Utils;
38 import com.android.managedprovisioning.model.ProvisioningParams;
39 import com.android.managedprovisioning.task.AddWifiNetworkTask;
40 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask;
41 import com.android.managedprovisioning.task.DisallowAddUserTask;
42 import com.android.managedprovisioning.task.DownloadPackageTask;
43 import com.android.managedprovisioning.task.InstallPackageTask;
44 import com.android.managedprovisioning.task.SetDevicePolicyTask;
45 
46 import java.util.Locale;
47 
48 /**
49  * This service does the work for the DeviceOwnerProvisioningActivity.
50  * Feedback is sent back to the activity via intents.
51  *
52  * <p>
53  * If the corresponding activity is killed and restarted, the service is
54  * called twice. The service will not start the provisioning flow a second time, but instead
55  * send a status update to the activity.
56  * </p>
57  */
58 public class DeviceOwnerProvisioningService extends Service {
59     private static final boolean DEBUG = false; // To control logging.
60 
61     private static final String DEVICE_OWNER = "deviceOwner";
62 
63     /**
64      * Intent action to activate the CDMA phone connection by OTASP.
65      * This is not necessary for a GSM phone connection, which is activated automatically.
66      * String must agree with the constants in com.android.phone.InCallScreenShowActivation.
67      */
68     private static final String ACTION_PERFORM_CDMA_PROVISIONING =
69             "com.android.phone.PERFORM_CDMA_PROVISIONING";
70 
71     // Intent actions and extras for communication from DeviceOwnerProvisioningService to Activity.
72     protected static final String ACTION_PROVISIONING_SUCCESS =
73             "com.android.managedprovisioning.provisioning_success";
74     protected static final String ACTION_PROVISIONING_ERROR =
75             "com.android.managedprovisioning.error";
76     protected static final String EXTRA_USER_VISIBLE_ERROR_ID_KEY =
77             "UserVisibleErrorMessage-Id";
78     protected static final String EXTRA_FACTORY_RESET_REQUIRED =
79             "FactoryResetRequired";
80     protected static final String ACTION_PROGRESS_UPDATE =
81             "com.android.managedprovisioning.progress_update";
82     protected static final String EXTRA_PROGRESS_MESSAGE_ID_KEY =
83             "ProgressMessageId";
84     protected static final String ACTION_REQUEST_WIFI_PICK =
85             "com.android.managedprovisioning.request_wifi_pick";
86 
87     // Indicates whether provisioning has started.
88     private boolean mProvisioningInFlight = false;
89 
90     // MessageId of the last progress message.
91     private int mLastProgressMessage = -1;
92 
93     // MessageId of the last error message.
94     private int mLastErrorMessage = -1;
95 
96     // Indicates whether reverting the provisioning process up till now requires a factory reset.
97     // Is false at the start and flips to true after the first irrevertible action.
98     private boolean mFactoryResetRequired = false;
99 
100     // Indicates whether provisioning has finished successfully (service waiting to stop).
101     private volatile boolean mDone = false;
102 
103     // Provisioning tasks.
104     private AddWifiNetworkTask mAddWifiNetworkTask;
105     private DownloadPackageTask mDownloadPackageTask;
106     private InstallPackageTask mInstallPackageTask;
107     private SetDevicePolicyTask mSetDevicePolicyTask;
108     private DeleteNonRequiredAppsTask mDeleteNonRequiredAppsTask;
109     private DisallowAddUserTask mDisallowAddUserTask;
110 
111     private ProvisioningParams mParams;
112 
113     private final Utils mUtils = new Utils();
114 
115     @Override
onStartCommand(final Intent intent, int flags, int startId)116     public int onStartCommand(final Intent intent, int flags, int startId) {
117         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONSTARTCOMMAND.");
118 
119         synchronized (this) { // Make operations on mProvisioningInFlight atomic.
120             if (mProvisioningInFlight) {
121                 if (DEBUG) ProvisionLogger.logd("Provisioning already in flight.");
122 
123                 sendProgressUpdateToActivity();
124 
125                 // Send error message if currently in error state.
126                 if (mLastErrorMessage >= 0) {
127                     sendError();
128                 }
129 
130                 // Send success if provisioning was successful.
131                 if (mDone) {
132                     onProvisioningSuccess();
133                 }
134             } else {
135                 mProvisioningInFlight = true;
136                 if (DEBUG) ProvisionLogger.logd("First start of the service.");
137                 progressUpdate(R.string.progress_data_process);
138 
139                 // Load the ProvisioningParams (from message in Intent).
140                 mParams = (ProvisioningParams) intent.getParcelableExtra(
141                         ProvisioningParams.EXTRA_PROVISIONING_PARAMS);
142 
143                 // Do the work on a separate thread.
144                 new Thread(new Runnable() {
145                     public void run() {
146                         initializeProvisioningEnvironment(mParams);
147                         startDeviceOwnerProvisioning(mParams);
148                     }
149                 }).start();
150             }
151         }
152         return START_NOT_STICKY;
153     }
154 
155     /**
156      * This is the core method of this class. It goes through every provisioning step.
157      * Each task checks if it is required and executes if it is.
158      */
startDeviceOwnerProvisioning(final ProvisioningParams params)159     private void startDeviceOwnerProvisioning(final ProvisioningParams params) {
160         if (DEBUG) ProvisionLogger.logd("Starting device owner provisioning");
161 
162         // Construct Tasks. Do not start them yet.
163         mAddWifiNetworkTask = new AddWifiNetworkTask(this, params.wifiInfo,
164                 new AddWifiNetworkTask.Callback() {
165                     @Override
166                     public void onSuccess() {
167                         progressUpdate(R.string.progress_download);
168                         mDownloadPackageTask.run();
169                     }
170 
171                     @Override
172                     public void onError(){
173                         error(R.string.device_owner_error_wifi,
174                                 false /* do not require factory reset */);
175                     }
176                 });
177 
178         mDownloadPackageTask = new DownloadPackageTask(this,
179                 new DownloadPackageTask.Callback() {
180                     @Override
181                     public void onSuccess() {
182                         progressUpdate(R.string.progress_install);
183                         mInstallPackageTask.addInstallIfNecessary(
184                                 params.inferDeviceAdminPackageName(),
185                                 mDownloadPackageTask.getDownloadedPackageLocation(DEVICE_OWNER));
186                         mInstallPackageTask.run();
187                     }
188 
189                     @Override
190                     public void onError(int errorCode) {
191                         switch(errorCode) {
192                             case DownloadPackageTask.ERROR_HASH_MISMATCH:
193                                 error(R.string.device_owner_error_hash_mismatch);
194                                 break;
195                             case DownloadPackageTask.ERROR_DOWNLOAD_FAILED:
196                                 error(R.string.device_owner_error_download_failed);
197                                 break;
198                             default:
199                                 error(R.string.device_owner_error_general);
200                                 break;
201                         }
202                     }
203                 });
204 
205         // Add packages to download to the DownloadPackageTask.
206         mDownloadPackageTask.addDownloadIfNecessary(params.inferDeviceAdminPackageName(),
207                 params.deviceAdminDownloadInfo, DEVICE_OWNER);
208 
209         mInstallPackageTask = new InstallPackageTask(this,
210                 new InstallPackageTask.Callback() {
211                     @Override
212                     public void onSuccess() {
213                         progressUpdate(R.string.progress_set_owner);
214                         try {
215                             // Now that the app has been installed, we can look for the device admin
216                             // component in it.
217                             mSetDevicePolicyTask.run(mParams.inferDeviceAdminComponentName(
218                                     DeviceOwnerProvisioningService.this));
219                         } catch (IllegalProvisioningArgumentException e) {
220                             error(R.string.device_owner_error_general);
221                             ProvisionLogger.loge("Failed to infer the device admin component name",
222                                     e);
223                             return;
224                         }
225                     }
226 
227                     @Override
228                     public void onError(int errorCode) {
229                         switch(errorCode) {
230                             case InstallPackageTask.ERROR_PACKAGE_INVALID:
231                                 error(R.string.device_owner_error_package_invalid);
232                                 break;
233                             case InstallPackageTask.ERROR_INSTALLATION_FAILED:
234                                 error(R.string.device_owner_error_installation_failed);
235                                 break;
236                             default:
237                                 error(R.string.device_owner_error_general);
238                                 break;
239                         }
240                     }
241                 });
242 
243         mSetDevicePolicyTask = new SetDevicePolicyTask(this,
244                 getResources().getString(R.string.default_owned_device_username),
245                 new SetDevicePolicyTask.Callback() {
246                     @Override
247                     public void onSuccess() {
248                         mDeleteNonRequiredAppsTask.run();
249                     }
250 
251                     @Override
252                     public void onError() {
253                         error(R.string.device_owner_error_general);
254                     }
255                 });
256 
257         // For split system user devices that will have a system device owner, don't adjust the set
258         // of enabled packages in the system user as we expect the right set of packages to be
259         // enabled for the system user out of the box. For other devices, the set of available
260         // packages can vary depending on management state.
261         boolean leaveAllSystemAppsEnabled = params.leaveAllSystemAppsEnabled ||
262                 params.provisioningAction.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE);
263         mDeleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask(
264                 this, params.inferDeviceAdminPackageName(),
265                 DeleteNonRequiredAppsTask.DEVICE_OWNER, true /* creating new profile */,
266                 UserHandle.myUserId(), leaveAllSystemAppsEnabled,
267                 new DeleteNonRequiredAppsTask.Callback() {
268                     @Override
269                     public void onSuccess() {
270                         mDisallowAddUserTask.maybeDisallowAddUsers();
271 
272                         // Done with provisioning. Success.
273                         onProvisioningSuccess();
274                     }
275 
276                     @Override
277                     public void onError() {
278                         error(R.string.device_owner_error_general);
279                     }
280                 });
281 
282         mDisallowAddUserTask = new DisallowAddUserTask((UserManager) getSystemService(USER_SERVICE),
283                 UserHandle.myUserId(), UserManager.isSplitSystemUser());
284 
285         // Start first task, which starts next task in its callback, etc.
286         progressUpdate(R.string.progress_connect_to_wifi);
287         mAddWifiNetworkTask.run();
288     }
289 
error(int dialogMessage)290     private void error(int dialogMessage) {
291         error(dialogMessage, true /* require factory reset */);
292     }
293 
error(int dialogMessage, boolean factoryResetRequired)294     private void error(int dialogMessage, boolean factoryResetRequired) {
295         mLastErrorMessage = dialogMessage;
296         if (factoryResetRequired) {
297             mFactoryResetRequired = true;
298         }
299         sendError();
300         // Wait for stopService() call from the activity.
301     }
302 
sendError()303     private void sendError() {
304         if (DEBUG) {
305             ProvisionLogger.logd("Reporting Error: " + getResources()
306                 .getString(mLastErrorMessage));
307         }
308         Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
309         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
310         intent.putExtra(EXTRA_USER_VISIBLE_ERROR_ID_KEY, mLastErrorMessage);
311         intent.putExtra(EXTRA_FACTORY_RESET_REQUIRED, mFactoryResetRequired);
312         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
313     }
314 
progressUpdate(int progressMessage)315     private void progressUpdate(int progressMessage) {
316         if (DEBUG) {
317             ProvisionLogger.logd("Reporting progress update: " + getResources()
318                 .getString(progressMessage));
319         }
320         mLastProgressMessage = progressMessage;
321         sendProgressUpdateToActivity();
322     }
323 
sendProgressUpdateToActivity()324     private void sendProgressUpdateToActivity() {
325         Intent intent = new Intent(ACTION_PROGRESS_UPDATE);
326         intent.putExtra(EXTRA_PROGRESS_MESSAGE_ID_KEY, mLastProgressMessage);
327         intent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
328         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
329     }
330 
onProvisioningSuccess()331     private void onProvisioningSuccess() {
332         // Copying an account needs to happen late in the provisioning process to allow the current
333         // user to be started, but before we tell the MDM that provisioning succeeded.
334         maybeCopyAccount();
335 
336         if (DEBUG) ProvisionLogger.logd("Reporting success.");
337         mDone = true;
338 
339         // Set DPM userProvisioningState appropriately and persists mParams for use during
340         // FinalizationActivity if necessary.
341         mUtils.markUserProvisioningStateInitiallyDone(this, mParams);
342 
343         Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
344         successIntent.setClass(this, DeviceOwnerProvisioningActivity.ServiceMessageReceiver.class);
345         LocalBroadcastManager.getInstance(this).sendBroadcast(successIntent);
346         // Wait for stopService() call from the activity.
347     }
348 
maybeCopyAccount()349     private void maybeCopyAccount() {
350         if (!UserManager.isSplitSystemUser()) {
351             // Only one user involved in this case.
352             return;
353         }
354 
355         mUtils.maybeCopyAccount(DeviceOwnerProvisioningService.this,
356                 mParams.accountToMigrate, UserHandle.SYSTEM,
357                 Process.myUserHandle());
358     }
359 
initializeProvisioningEnvironment(ProvisioningParams params)360     private void initializeProvisioningEnvironment(ProvisioningParams params) {
361         setTimeAndTimezone(params.timeZone, params.localTime);
362         setLocale(params.locale);
363 
364         // Start CDMA activation to enable phone calls.
365         final Intent intent = new Intent(ACTION_PERFORM_CDMA_PROVISIONING);
366         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
367         if (DEBUG) ProvisionLogger.logd("Starting cdma activation activity");
368         startActivity(intent); // Activity will be a Nop if not a CDMA device.
369     }
370 
setTimeAndTimezone(String timeZone, long localTime)371     private void setTimeAndTimezone(String timeZone, long localTime) {
372         try {
373             final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
374             if (timeZone != null) {
375                 if (DEBUG) ProvisionLogger.logd("Setting time zone to " + timeZone);
376                 am.setTimeZone(timeZone);
377             }
378             if (localTime > 0) {
379                 if (DEBUG) ProvisionLogger.logd("Setting time to " + localTime);
380                 am.setTime(localTime);
381             }
382         } catch (Exception e) {
383             ProvisionLogger.loge("Alarm manager failed to set the system time/timezone.");
384             // Do not stop provisioning process, but ignore this error.
385         }
386     }
387 
setLocale(Locale locale)388     private void setLocale(Locale locale) {
389         if (locale == null || locale.equals(Locale.getDefault())) {
390             return;
391         }
392         try {
393             if (DEBUG) ProvisionLogger.logd("Setting locale to " + locale);
394             // If locale is different from current locale this results in a configuration change,
395             // which will trigger the restarting of the activity.
396             LocalePicker.updateLocale(locale);
397         } catch (Exception e) {
398             ProvisionLogger.loge("Failed to set the system locale.");
399             // Do not stop provisioning process, but ignore this error.
400         }
401     }
402 
403     @Override
onCreate()404     public void onCreate () {
405         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONCREATE.");
406     }
407 
408     @Override
onDestroy()409     public void onDestroy () {
410         if (DEBUG) ProvisionLogger.logd("Device owner provisioning service ONDESTROY");
411         if (mAddWifiNetworkTask != null) {
412             mAddWifiNetworkTask.cleanUp();
413         }
414         if (mDownloadPackageTask != null) {
415             mDownloadPackageTask.cleanUp();
416         }
417     }
418 
419     @Override
onBind(Intent intent)420     public IBinder onBind(Intent intent) {
421         return null;
422     }
423 }
424