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_ACCOUNT_TO_MIGRATE;
21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
23 import static android.Manifest.permission.BIND_DEVICE_ADMIN;
24 
25 import android.accounts.Account;
26 import android.accounts.AccountManager;
27 import android.accounts.AuthenticatorException;
28 import android.accounts.OperationCanceledException;
29 import android.app.Activity;
30 import android.app.ActivityManagerNative;
31 import android.app.IActivityManager;
32 import android.app.Service;
33 import android.app.admin.DevicePolicyManager;
34 import android.content.BroadcastReceiver;
35 import android.content.ComponentName;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.pm.ActivityInfo;
39 import android.content.pm.IPackageManager;
40 import android.content.pm.PackageInfo;
41 import android.content.pm.PackageManager;
42 import android.content.pm.PackageManager.NameNotFoundException;
43 import android.content.pm.UserInfo;
44 import android.os.AsyncTask;
45 import android.os.IBinder;
46 import android.os.Parcelable;
47 import android.os.PersistableBundle;
48 import android.os.Process;
49 import android.os.RemoteException;
50 import android.os.ServiceManager;
51 import android.os.UserHandle;
52 import android.os.UserManager;
53 import android.provider.MediaStore;
54 import android.support.v4.content.LocalBroadcastManager;
55 import android.text.TextUtils;
56 
57 import com.android.managedprovisioning.CrossProfileIntentFiltersHelper;
58 import com.android.managedprovisioning.task.DeleteNonRequiredAppsTask;
59 
60 import java.io.IOException;
61 
62 /**
63  * Service that runs the profile owner provisioning.
64  *
65  * <p>This service is started from and sends updates to the {@link ProfileOwnerProvisioningActivity},
66  * which contains the provisioning UI.
67  */
68 public class ProfileOwnerProvisioningService extends Service {
69     // Extra keys for reporting back success to the activity.
70     public static final String EXTRA_PROFILE_USER_ID =
71             "com.android.managedprovisioning.extra.profile_user_id";
72     public static final String EXTRA_PROFILE_USER_SERIAL_NUMBER =
73             "com.android.managedprovisioning.extra.profile_user_serial_number";
74     public static final String EXTRA_PENDING_SUCCESS_INTENT =
75             "com.android.managedprovisioning.extra.pending_success_intent";
76 
77     // Intent actions for communication with DeviceOwnerProvisioningService.
78     public static final String ACTION_PROVISIONING_SUCCESS =
79             "com.android.managedprovisioning.provisioning_success";
80     public static final String ACTION_PROVISIONING_ERROR =
81             "com.android.managedprovisioning.error";
82     public static final String ACTION_PROVISIONING_CANCELLED =
83             "com.android.managedprovisioning.cancelled";
84     public static final String EXTRA_LOG_MESSAGE_KEY = "ProvisioingErrorLogMessage";
85 
86     private String mMdmPackageName;
87     private ComponentName mActiveAdminComponentName;
88 
89     // PersistableBundle extra received in starting intent.
90     // Should be passed through to device management application when provisioning is complete.
91     private PersistableBundle mAdminExtrasBundle;
92     private Account mAccountToMigrate;
93 
94     private IPackageManager mIpm;
95     private UserInfo mManagedProfileUserInfo;
96     private AccountManager mAccountManager;
97     private UserManager mUserManager;
98 
99     private int mStartIdProvisioning;
100     private AsyncTask<Intent, Void, Void> runnerTask;
101 
102     // MessageId of the last error message.
103     private String mLastErrorMessage = null;
104 
105     private boolean mDone = false;
106     private boolean mCancelInFuture = false;
107 
108     private class RunnerTask extends AsyncTask<Intent, Void, Void> {
109         @Override
doInBackground(Intent .... intents)110         protected Void doInBackground(Intent ... intents) {
111             initialize(intents[0]);
112             startManagedProfileProvisioning();
113             return null;
114         }
115     }
116 
117     @Override
onCreate()118     public void onCreate() {
119         super.onCreate();
120 
121         mIpm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
122         mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
123         mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
124 
125         runnerTask = new RunnerTask();
126     }
127 
128     @Override
onStartCommand(final Intent intent, int flags, int startId)129     public int onStartCommand(final Intent intent, int flags, int startId) {
130         if (ProfileOwnerProvisioningActivity.ACTION_CANCEL_PROVISIONING.equals(intent.getAction())) {
131             ProvisionLogger.logd("Cancelling profile owner provisioning service");
132             cancelProvisioning();
133             return START_NOT_STICKY;
134         }
135 
136         ProvisionLogger.logd("Starting profile owner provisioning service");
137 
138         try {
139             runnerTask.execute(intent);
140         } catch (IllegalStateException e) {
141             // runnerTask is either in progress, or finished.
142             ProvisionLogger.logd(
143                     "ProfileOwnerProvisioningService: Provisioning already started, "
144                     + "second provisioning intent not being processed, only reporting status.");
145             reportStatus();
146         }
147         return START_NOT_STICKY;
148     }
149 
reportStatus()150     private void reportStatus() {
151         if (mLastErrorMessage != null) {
152             sendError();
153         }
154         synchronized (this) {
155             if (mDone) {
156                 notifyActivityOfSuccess();
157             }
158         }
159     }
160 
cancelProvisioning()161     private void cancelProvisioning() {
162         synchronized (this) {
163             if (!mDone) {
164                 mCancelInFuture = true;
165                 return;
166             }
167             cleanup();
168         }
169     }
170 
initialize(Intent intent)171     private void initialize(Intent intent) {
172         mMdmPackageName = intent.getStringExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME);
173         mAccountToMigrate = (Account) intent.getParcelableExtra(
174                 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE);
175         if (mAccountToMigrate != null) {
176             ProvisionLogger.logi("Migrating account to managed profile");
177         }
178 
179         // Cast is guaranteed by check in Activity.
180         mAdminExtrasBundle  = (PersistableBundle) intent.getParcelableExtra(
181                 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE);
182 
183         mActiveAdminComponentName = getAdminReceiverComponent(mMdmPackageName);
184     }
185 
186     /**
187      * Find the Device admin receiver component from the manifest.
188      */
getAdminReceiverComponent(String packageName)189     private ComponentName getAdminReceiverComponent(String packageName) {
190         ComponentName adminReceiverComponent = null;
191 
192         try {
193             PackageInfo pi = getPackageManager().getPackageInfo(packageName,
194                     PackageManager.GET_RECEIVERS);
195             for (ActivityInfo ai : pi.receivers) {
196                 if (!TextUtils.isEmpty(ai.permission) &&
197                         ai.permission.equals(BIND_DEVICE_ADMIN)) {
198                     adminReceiverComponent = new ComponentName(packageName, ai.name);
199 
200                 }
201             }
202         } catch (NameNotFoundException e) {
203             error("Error: The provided mobile device management package does not define a device"
204                     + "admin receiver component in its manifest.");
205         }
206         return adminReceiverComponent;
207     }
208 
209     /**
210      * This is the core method of this class. It goes through every provisioning step.
211      */
startManagedProfileProvisioning()212     private void startManagedProfileProvisioning() {
213 
214         ProvisionLogger.logd("Starting managed profile provisioning");
215 
216         // Work through the provisioning steps in their corresponding order
217         createProfile(getString(R.string.default_managed_profile_name));
218         if (mManagedProfileUserInfo != null) {
219             new DeleteNonRequiredAppsTask(this,
220                     mMdmPackageName, mManagedProfileUserInfo.id,
221                     R.array.required_apps_managed_profile,
222                     R.array.vendor_required_apps_managed_profile,
223                     true /* We are creating a new profile */,
224                     true /* Disable INSTALL_SHORTCUT listeners */,
225                     new DeleteNonRequiredAppsTask.Callback() {
226 
227                         @Override
228                         public void onSuccess() {
229                             setUpProfileAndFinish();
230                         }
231 
232                         @Override
233                         public void onError() {
234                             error("Delete non required apps task failed.");
235                         }
236                     }).run();
237         }
238     }
239 
240     /**
241      * Called when the new profile is ready for provisioning (the profile is created and all the
242      * apps not needed have been deleted).
243      */
setUpProfileAndFinish()244     private void setUpProfileAndFinish() {
245         installMdmOnManagedProfile();
246         setMdmAsActiveAdmin();
247         setMdmAsManagedProfileOwner();
248         CrossProfileIntentFiltersHelper.setFilters(
249                 getPackageManager(), getUserId(), mManagedProfileUserInfo.id);
250 
251         if (!startManagedProfile(mManagedProfileUserInfo.id)) {
252             error("Could not start user in background");
253             return;
254         }
255         copyAccount(mAccountToMigrate);
256         synchronized (this) {
257             mDone = true;
258             if (mCancelInFuture) {
259                 cleanup();
260             } else {
261                 // Notify activity of success.
262                 notifyActivityOfSuccess();
263             }
264         }
265     }
266 
267     /**
268      * Initialize the user that underlies the managed profile.
269      * This is required so that the provisioning complete broadcast can be sent across to the
270      * profile and apps can run on it.
271      */
startManagedProfile(int userId)272     private boolean startManagedProfile(int userId)  {
273         ProvisionLogger.logd("Starting user in background");
274         IActivityManager iActivityManager = ActivityManagerNative.getDefault();
275         try {
276             return iActivityManager.startUserInBackground(userId);
277         } catch (RemoteException neverThrown) {
278             // Never thrown, as we are making local calls.
279             ProvisionLogger.loge("This should not happen.", neverThrown);
280         }
281         return false;
282     }
283 
notifyActivityOfSuccess()284     private void notifyActivityOfSuccess() {
285         // Compose the intent that will be fired by the activity.
286         Intent completeIntent = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE);
287         completeIntent.setComponent(mActiveAdminComponentName);
288         completeIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES |
289                 Intent.FLAG_RECEIVER_FOREGROUND);
290         if (mAdminExtrasBundle != null) {
291             completeIntent.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
292                     mAdminExtrasBundle);
293         }
294 
295         Intent successIntent = new Intent(ACTION_PROVISIONING_SUCCESS);
296         successIntent.putExtra(EXTRA_PROFILE_USER_ID, mManagedProfileUserInfo.id);
297         successIntent.putExtra(EXTRA_PENDING_SUCCESS_INTENT, completeIntent);
298         successIntent.putExtra(EXTRA_PROFILE_USER_SERIAL_NUMBER,
299                 mManagedProfileUserInfo.serialNumber);
300         LocalBroadcastManager.getInstance(ProfileOwnerProvisioningService.this)
301                 .sendBroadcast(successIntent);
302     }
303 
copyAccount(Account account)304     private void copyAccount(Account account) {
305         if (account == null) {
306             ProvisionLogger.logd("No account to migrate to the managed profile.");
307             return;
308         }
309         ProvisionLogger.logd("Attempting to copy account to user " + mManagedProfileUserInfo.id);
310         try {
311             if (mAccountManager.copyAccountToUser(account, mManagedProfileUserInfo.getUserHandle(),
312                     /* callback= */ null, /* handler= */ null).getResult()) {
313                 ProvisionLogger.logi("Copied account to user " + mManagedProfileUserInfo.id);
314             } else {
315                 ProvisionLogger.loge("Could not copy account to user "
316                         + mManagedProfileUserInfo.id);
317             }
318         } catch (OperationCanceledException | AuthenticatorException | IOException e) {
319             ProvisionLogger.logw("Exception copying account to user " + mManagedProfileUserInfo.id,
320                     e);
321         }
322     }
323 
createProfile(String profileName)324     private void createProfile(String profileName) {
325 
326         ProvisionLogger.logd("Creating managed profile with name " + profileName);
327 
328         mManagedProfileUserInfo = mUserManager.createProfileForUser(profileName,
329                 UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_DISABLED,
330                 Process.myUserHandle().getIdentifier());
331 
332         if (mManagedProfileUserInfo == null) {
333             if (UserManager.getMaxSupportedUsers() == mUserManager.getUserCount()) {
334                 error("Profile creation failed, maximum number of users reached.");
335             } else {
336                 error("Couldn't create profile. Reason unknown.");
337             }
338         }
339     }
340 
installMdmOnManagedProfile()341     private void installMdmOnManagedProfile() {
342         ProvisionLogger.logd("Installing mobile device management app " + mMdmPackageName +
343               " on managed profile");
344 
345         try {
346             int status = mIpm.installExistingPackageAsUser(
347                 mMdmPackageName, mManagedProfileUserInfo.id);
348             switch (status) {
349               case PackageManager.INSTALL_SUCCEEDED:
350                   return;
351               case PackageManager.INSTALL_FAILED_USER_RESTRICTED:
352                   // Should not happen because we're not installing a restricted user
353                   error("Could not install mobile device management app on managed "
354                           + "profile because the user is restricted");
355               case PackageManager.INSTALL_FAILED_INVALID_URI:
356                   // Should not happen because we already checked
357                   error("Could not install mobile device management app on managed "
358                           + "profile because the package could not be found");
359               default:
360                   error("Could not install mobile device management app on managed "
361                           + "profile. Unknown status: " + status);
362             }
363         } catch (RemoteException neverThrown) {
364             // Never thrown, as we are making local calls.
365             ProvisionLogger.loge("This should not happen.", neverThrown);
366         }
367     }
368 
setMdmAsManagedProfileOwner()369     private void setMdmAsManagedProfileOwner() {
370         ProvisionLogger.logd("Setting package " + mMdmPackageName + " as managed profile owner.");
371 
372         DevicePolicyManager dpm =
373                 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
374         if (!dpm.setProfileOwner(mActiveAdminComponentName, mMdmPackageName,
375                 mManagedProfileUserInfo.id)) {
376             ProvisionLogger.logw("Could not set profile owner.");
377             error("Could not set profile owner.");
378         }
379     }
380 
setMdmAsActiveAdmin()381     private void setMdmAsActiveAdmin() {
382         ProvisionLogger.logd("Setting package " + mMdmPackageName + " as active admin.");
383 
384         DevicePolicyManager dpm =
385                 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
386         dpm.setActiveAdmin(mActiveAdminComponentName, true /* refreshing*/,
387                 mManagedProfileUserInfo.id);
388     }
389 
error(String dialogMessage)390     private void error(String dialogMessage) {
391         mLastErrorMessage = dialogMessage;
392         sendError();
393     }
394 
sendError()395     private void sendError() {
396         Intent intent = new Intent(ACTION_PROVISIONING_ERROR);
397         intent.putExtra(EXTRA_LOG_MESSAGE_KEY, mLastErrorMessage);
398         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
399     }
400 
401     /**
402      * Performs cleanup of the device on failure.
403      */
cleanup()404     private void cleanup() {
405         // The only cleanup we need to do is remove the profile we created.
406         if (mManagedProfileUserInfo != null) {
407             ProvisionLogger.logd("Removing managed profile");
408             mUserManager.removeUser(mManagedProfileUserInfo.id);
409         }
410         Intent cancelIntent = new Intent(ACTION_PROVISIONING_CANCELLED);
411         LocalBroadcastManager.getInstance(ProfileOwnerProvisioningService.this)
412                 .sendBroadcast(cancelIntent);
413     }
414 
415     @Override
onBind(Intent intent)416     public IBinder onBind(Intent intent) {
417         return null;
418     }
419 }
420