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