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