From cc30b0e7901f753fabbfa08f10d0b3f9b5a54144 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Fri, 20 May 2016 14:41:22 -0700 Subject: [PATCH] Adding RetailModeService to handle retail mode The service listens for the global setting DEVICE_DEMO_MODE and switches device to demo mode when it is changed to 1. Also, acquires the wakelock to keep the screen on and puts up a notification to wipe and reset the demo session when in demo mode. Bug: 27280140 Change-Id: If1843016889ec2c50818c67432d60f33063e0986 --- .../server/am/ActivityManagerService.java | 5 + .../server/am/RetailDemoModeService.java | 179 ++++++++++++++++++ .../com/android/server/am/UserController.java | 28 +-- .../android/server/pm/UserManagerService.java | 3 +- .../java/com/android/server/SystemServer.java | 8 + 5 files changed, 195 insertions(+), 28 deletions(-) create mode 100644 services/core/java/com/android/server/am/RetailDemoModeService.java diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index dc313e2d6041d..2093bbb27add5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -20908,6 +20908,11 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "No user info for user #" + targetUserId); return false; } + if (!targetUserInfo.isDemo() && UserManager.isDeviceInDemoMode(mContext)) { + Slog.w(TAG, "Cannot switch to non-demo user #" + targetUserId + + " when device is in demo mode"); + return false; + } if (!targetUserInfo.supportsSwitchTo()) { Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported"); return false; diff --git a/services/core/java/com/android/server/am/RetailDemoModeService.java b/services/core/java/com/android/server/am/RetailDemoModeService.java new file mode 100644 index 0000000000000..bf2ba93bb7e98 --- /dev/null +++ b/services/core/java/com/android/server/am/RetailDemoModeService.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.am; + +import android.app.ActivityManagerNative; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.UserInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.PowerManager; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import android.util.Slog; + +import com.android.server.ServiceThread; +import com.android.server.SystemService; +import com.android.server.pm.UserManagerService; + +public class RetailDemoModeService extends SystemService { + private static final boolean DEBUG = false; + + private static final String TAG = RetailDemoModeService.class.getSimpleName(); + private static final String DEMO_USER_NAME = "Demo"; + + private static final long SCREEN_WAKEUP_DELAY = 5000; + + private ActivityManagerService mAms; + private UserManagerService mUms; + private PowerManager mPm; + private PowerManager.WakeLock mWakeLock; + private Handler mHandler; + private ServiceThread mHandlerThread; + + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!UserManager.isDeviceInDemoMode(getContext())) { + return; + } + switch (intent.getAction()) { + case Intent.ACTION_SCREEN_OFF: + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + mWakeLock.acquire(); + } + }, SCREEN_WAKEUP_DELAY); + break; + } + } + }; + + public RetailDemoModeService(Context context) { + super(context); + } + + private void createAndSwitchToDemoUser() { + if (DEBUG) { + Slog.d(TAG, "Switching to a new demo user"); + } + mHandler.post(new Runnable() { + @Override + public void run() { + UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME, + UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL); + if (demoUser != null) { + getActivityManager().switchUser(demoUser.id); + } + } + }); + } + + private ActivityManagerService getActivityManager() { + if (mAms == null) { + mAms = (ActivityManagerService) ActivityManagerNative.getDefault(); + } + return mAms; + } + + private UserManagerService getUserManager() { + if (mUms == null) { + mUms = (UserManagerService) UserManagerService.Stub + .asInterface(ServiceManager.getService(Context.USER_SERVICE)); + } + return mUms; + } + + private void registerSettingsChangeObserver() { + final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE); + final ContentResolver cr = getContext().getContentResolver(); + final ContentObserver deviceDemoModeSettingObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (deviceDemoModeUri.equals(uri)) { + if (UserManager.isDeviceInDemoMode(getContext())) { + createAndSwitchToDemoUser(); + } + } + } + }; + cr.registerContentObserver(deviceDemoModeUri, false, deviceDemoModeSettingObserver, + UserHandle.USER_SYSTEM); + } + + private void registerBroadcastReceiver() { + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); + } + + @Override + public void onStart() { + if (DEBUG) { + Slog.d(TAG, "Service starting up"); + } + mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, + false); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper(), null, true); + } + + @Override + public void onBootPhase(int bootPhase) { + if (bootPhase != PHASE_THIRD_PARTY_APPS_CAN_START) { + return; + } + mPm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); + mWakeLock = mPm + .newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG); + if (UserManager.isDeviceInDemoMode(getContext())) { + createAndSwitchToDemoUser(); + } + registerSettingsChangeObserver(); + registerBroadcastReceiver(); + } + + @Override + public void onSwitchUser(int userId) { + if (DEBUG) { + Slog.d(TAG, "onSwitchUser: " + userId); + } + UserInfo ui = getUserManager().getUserInfo(userId); + if (!ui.isDemo()) { + if (UserManager.isDeviceInDemoMode(getContext())) { + Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode"); + } else if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + return; + } + if (!mWakeLock.isHeld()) { + mWakeLock.acquire(); + } + } +} diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 2edbfe4815e50..4fe17405013e9 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -223,8 +223,7 @@ final class UserController { private void finishUserBoot(UserState uss, IIntentReceiver resultTo) { final int userId = uss.mHandle.getIdentifier(); - boolean deviceInDemoMode = UserManager.isDeviceInDemoMode(mService.mContext); - boolean switchToDemoUser = false; + Slog.d(TAG, "Finishing user boot " + userId); synchronized (mService) { // Bail if we ended up with a stale user @@ -261,32 +260,7 @@ final class UserController { } else { maybeUnlockUser(userId); } - if (deviceInDemoMode && mCurrentUserId == UserHandle.USER_SYSTEM) { - switchToDemoUser = true; - } } - - if (switchToDemoUser) { - doSwitchToDemoUser(); - } - } - - private void doSwitchToDemoUser() { - mHandler.post(new Runnable() { - @Override - public void run() { - // Remove any demo users first - for (UserInfo user: mUserManager.getUsers(true)) { - if (user.isDemo()) { - mUserManager.removeUser(user.id); - } - } - UserInfo demoUser = mUserManager.createUser("Demo", UserInfo.FLAG_DEMO); - if (demoUser != null) { - mService.switchUser(demoUser.id); - } - } - }); } /** diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index ff17552c0f020..4541e2ecf2c9e 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2074,7 +2074,8 @@ public class UserManagerService extends IUserManager.Stub { return null; } } - if (!UserManager.isSplitSystemUser() && (flags & UserInfo.FLAG_EPHEMERAL) != 0) { + if (!UserManager.isSplitSystemUser() && (flags & UserInfo.FLAG_EPHEMERAL) != 0 + && (flags & UserInfo.FLAG_DEMO) == 0) { Log.e(LOG_TAG, "Ephemeral users are supported on split-system-user systems only."); return null; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index e306d8925f0bf..38f609c150be9 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -42,7 +42,9 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.os.UserManager; import android.os.storage.IMountService; +import android.provider.Settings; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Slog; @@ -55,6 +57,7 @@ import com.android.internal.os.ZygoteInit; import com.android.internal.widget.ILockSettings; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.am.ActivityManagerService; +import com.android.server.am.RetailDemoModeService; import com.android.server.audio.AudioService; import com.android.server.camera.CameraService; import com.android.server.clipboard.ClipboardService; @@ -1175,6 +1178,11 @@ public final class SystemServer { // MMS service broker mmsService = mSystemServiceManager.startService(MmsServiceBroker.class); + if (Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0 || + UserManager.isDeviceInDemoMode(mSystemContext)) { + mSystemServiceManager.startService(RetailDemoModeService.class); + } + // It is now time to start up the app processes... Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");