Introduce profile for lock screen apps

Introduces the profile to be used to run lock screen apps, instead
of sign-in profile.

The profile behavior will be similar to sign-in profile, but using
separate profile allows better isolation between apps running on
login screen and apps running on lock screen (which have different set
of app/extension APIs available), and make inference of lock screen
extension context type more straight forward. Also, this will enable
us to make lock screen app profile ephemeral.

This also updates the way lock_screen_extension context is calculated,
allows background pages in the profile for lock screen apps, and
disables app autoupdates in the lock screen profile (since the app
versions in the profile should correspond to app versions in the user
profile).

BUG=715781,734698

Review-Url: https://codereview.chromium.org/2945023002
Cr-Commit-Position: refs/heads/master@{#483123}
diff --git a/chrome/browser/chromeos/drive/file_system_util.cc b/chrome/browser/chromeos/drive/file_system_util.cc
index dbb73a7..4ff9eb2 100644
--- a/chrome/browser/chromeos/drive/file_system_util.cc
+++ b/chrome/browser/chromeos/drive/file_system_util.cc
@@ -158,7 +158,8 @@
   for (size_t i = 0; i < profiles.size(); ++i) {
     Profile* original_profile = profiles[i]->GetOriginalProfile();
     if (original_profile == profiles[i] &&
-        !chromeos::ProfileHelper::IsSigninProfile(original_profile)) {
+        !chromeos::ProfileHelper::IsSigninProfile(original_profile) &&
+        !chromeos::ProfileHelper::IsLockScreenAppProfile(original_profile)) {
       const base::FilePath base = GetDriveMountPointPath(original_profile);
       if (base == path || base.IsParent(path))
         return original_profile;
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 191e334..3dbdf66 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -347,9 +347,12 @@
 }
 
 void VolumeManager::Initialize() {
-  // If in Sign in profile, then skip mounting and listening for mount events.
-  if (chromeos::ProfileHelper::IsSigninProfile(profile_))
+  // If in the Sign in profile pr the lock screen app profile, skip mounting
+  // and listening for mount events.
+  if (chromeos::ProfileHelper::IsSigninProfile(profile_) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile_)) {
     return;
+  }
 
   // Register 'Downloads' folder for the profile to the file system.
   const base::FilePath downloads =
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util.cc b/chrome/browser/chromeos/file_system_provider/mount_path_util.cc
index cd568f0..36cd1404 100644
--- a/chrome/browser/chromeos/file_system_provider/mount_path_util.cc
+++ b/chrome/browser/chromeos/file_system_provider/mount_path_util.cc
@@ -100,7 +100,8 @@
     Profile* original_profile = profiles[i]->GetOriginalProfile();
 
     if (original_profile != profiles[i] ||
-        chromeos::ProfileHelper::IsSigninProfile(original_profile)) {
+        chromeos::ProfileHelper::IsSigninProfile(original_profile) ||
+        chromeos::ProfileHelper::IsLockScreenAppProfile(original_profile)) {
       continue;
     }
 
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
index bf7899fe..f0e141de 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
@@ -10,10 +10,14 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/lock_screen_apps/app_manager_impl.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/common/service_manager_connection.h"
 #include "extensions/browser/app_window/app_window.h"
@@ -44,7 +48,10 @@
 }
 
 StateController::StateController()
-    : binding_(this), app_window_observer_(this), session_observer_(this) {
+    : binding_(this),
+      app_window_observer_(this),
+      session_observer_(this),
+      weak_ptr_factory_(this) {
   DCHECK(!g_instance);
   DCHECK(IsEnabled());
 
@@ -65,6 +72,13 @@
   tray_action_ptr_.FlushForTesting();
 }
 
+void StateController::SetReadyCallbackForTesting(
+    const base::Closure& ready_callback) {
+  DCHECK(ready_callback_.is_null());
+
+  ready_callback_ = ready_callback;
+}
+
 void StateController::SetAppManagerForTesting(
     std::unique_ptr<AppManager> app_manager) {
   DCHECK(!app_manager_);
@@ -85,15 +99,49 @@
 }
 
 void StateController::SetPrimaryProfile(Profile* profile) {
+  g_browser_process->profile_manager()->CreateProfileAsync(
+      chromeos::ProfileHelper::GetLockScreenAppProfilePath(),
+      base::Bind(&StateController::OnProfilesReady,
+                 weak_ptr_factory_.GetWeakPtr(), profile),
+      base::string16() /* name */, "" /* icon_url*/,
+      "" /* supervised_user_id */);
+}
+
+void StateController::OnProfilesReady(Profile* primary_profile,
+                                      Profile* lock_screen_profile,
+                                      Profile::CreateStatus status) {
+  // Ignore CREATED status - wait for profile to be initialized before
+  // continuing.
+  if (status == Profile::CREATE_STATUS_CREATED)
+    return;
+
+  // On error, bail out - this will cause the lock screen apps to remain
+  // unavailable on the device.
+  if (status != Profile::CREATE_STATUS_INITIALIZED) {
+    LOG(ERROR) << "Failed to create profile for lock screen apps.";
+    return;
+  }
+
+  DCHECK(!lock_screen_profile_);
+
+  lock_screen_profile_ = lock_screen_profile;
+  lock_screen_profile_->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles,
+                                               true);
+
   // App manager might have been set previously by a test.
   if (!app_manager_)
     app_manager_ = base::MakeUnique<AppManagerImpl>();
-  app_manager_->Initialize(
-      profile,
-      chromeos::ProfileHelper::GetSigninProfile()->GetOriginalProfile());
+  app_manager_->Initialize(primary_profile,
+                           lock_screen_profile->GetOriginalProfile());
 
   session_observer_.Add(session_manager::SessionManager::Get());
   OnSessionStateChanged();
+
+  // SessionController is fully initialized at this point.
+  if (!ready_callback_.is_null()) {
+    ready_callback_.Run();
+    ready_callback_.Reset();
+  }
 }
 
 void StateController::AddObserver(StateObserver* observer) {
@@ -154,7 +202,7 @@
   if (lock_screen_note_state_ != TrayActionState::kLaunching)
     return nullptr;
 
-  if (!chromeos::ProfileHelper::GetSigninProfile()->IsSameProfile(
+  if (!lock_screen_profile_->IsSameProfile(
           Profile::FromBrowserContext(context))) {
     return nullptr;
   }
@@ -165,8 +213,8 @@
   // The ownership of the window is passed to the caller of this method.
   note_app_window_ =
       new extensions::AppWindow(context, app_delegate.release(), extension);
-  app_window_observer_.Add(extensions::AppWindowRegistry::Get(
-      chromeos::ProfileHelper::GetSigninProfile()));
+  app_window_observer_.Add(
+      extensions::AppWindowRegistry::Get(lock_screen_profile_));
   UpdateLockScreenNoteState(TrayActionState::kActive);
   return note_app_window_;
 }
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.h b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
index b180adc..f347e83 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.h
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
@@ -8,17 +8,17 @@
 #include <memory>
 
 #include "ash/public/interfaces/tray_action.mojom.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/lock_screen_apps/app_manager.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_observer.h"
+#include "chrome/browser/profiles/profile.h"
 #include "components/session_manager/core/session_manager_observer.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/api/app_runtime.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
-class Profile;
-
 namespace content {
 class BrowserContext;
 }
@@ -27,7 +27,7 @@
 class AppDelegate;
 class AppWindow;
 class Extension;
-}
+}  // namespace extensions
 
 namespace session_manager {
 class SessionManager;
@@ -63,6 +63,9 @@
   // Has to be called before |Initialize|.
   void SetTrayActionPtrForTesting(ash::mojom::TrayActionPtr tray_action_ptr);
   void FlushTrayActionForTesting();
+  // Sets the callback that will be run when the state controller is fully
+  // initialized and ready for action.
+  void SetReadyCallbackForTesting(const base::Closure& ready_callback);
   // Sets test AppManager implementation. Should be called before
   // |SetPrimaryProfile|
   void SetAppManagerForTesting(std::unique_ptr<AppManager> app_manager);
@@ -108,6 +111,14 @@
   void MoveToForeground();
 
  private:
+  // Called when profiles needed to run lock screen apps are ready - i.e. when
+  // primary user profile was set using |SetPrimaryProfile| and the profile in
+  // which app lock screen windows will be run creation is done.
+  // |status| - The lock screen profile creation status.
+  void OnProfilesReady(Profile* primary_profile,
+                       Profile* lock_screen_profile,
+                       Profile::CreateStatus status);
+
   // Called when app manager reports that note taking availability has changed.
   void OnNoteTakingAvailabilityChanged();
 
@@ -133,6 +144,8 @@
   mojo::Binding<ash::mojom::TrayActionClient> binding_;
   ash::mojom::TrayActionPtr tray_action_ptr_;
 
+  Profile* lock_screen_profile_ = nullptr;
+
   std::unique_ptr<AppManager> app_manager_;
 
   extensions::AppWindow* note_app_window_ = nullptr;
@@ -144,6 +157,14 @@
                  session_manager::SessionManagerObserver>
       session_observer_;
 
+  // If set, this callback will be run when the state controller is fully
+  // initialized. It can be used to throttle tests until state controller
+  // is ready for action - i.e. until the state controller starts reacting
+  // to session / app manager changes.
+  base::Closure ready_callback_;
+
+  base::WeakPtrFactory<StateController> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(StateController);
 };
 
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
index a28a1b8..d253fe7 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/test/scoped_command_line.h"
 #include "chrome/browser/chromeos/lock_screen_apps/app_manager.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_observer.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
@@ -328,34 +329,32 @@
 
     ASSERT_TRUE(lock_screen_apps::StateController::IsEnabled());
 
+    // Create fake lock screen app profile.
+    lock_screen_profile_ = profile_manager_.CreateTestingProfile(
+        chromeos::ProfileHelper::GetLockScreenAppProfileName());
+
+    InitExtensionSystem(profile());
+    InitExtensionSystem(lock_screen_profile());
+
+    std::unique_ptr<TestAppManager> app_manager =
+        base::MakeUnique<TestAppManager>(
+            &profile_, lock_screen_profile_->GetOriginalProfile());
+    app_manager_ = app_manager.get();
+
     state_controller_ = base::MakeUnique<lock_screen_apps::StateController>();
     state_controller_->SetTrayActionPtrForTesting(
         tray_action_.CreateInterfacePtrAndBind());
+    state_controller_->SetAppManagerForTesting(std::move(app_manager));
+    state_controller_->SetReadyCallbackForTesting(ready_waiter_.QuitClosure());
     state_controller_->Initialize();
     state_controller_->FlushTrayActionForTesting();
 
     state_controller_->AddObserver(&observer_);
-
-    // Create fake sign-in profile.
-    TestingProfile::Builder builder;
-    builder.SetPath(
-        profile_manager_.profiles_dir().AppendASCII(chrome::kInitialProfile));
-    signin_profile_ = builder.BuildIncognito(
-        profile_manager_.CreateTestingProfile(chrome::kInitialProfile));
-
-    InitExtensionSystem(profile());
-    InitExtensionSystem(signin_profile());
-
-    std::unique_ptr<TestAppManager> app_manager =
-        base::MakeUnique<TestAppManager>(&profile_,
-                                         signin_profile_->GetOriginalProfile());
-    app_manager_ = app_manager.get();
-    state_controller_->SetAppManagerForTesting(std::move(app_manager));
   }
 
   void TearDown() override {
     extensions::ExtensionSystem::Get(profile())->Shutdown();
-    extensions::ExtensionSystem::Get(signin_profile())->Shutdown();
+    extensions::ExtensionSystem::Get(lock_screen_profile())->Shutdown();
 
     state_controller_->RemoveObserver(&observer_);
     state_controller_.reset();
@@ -402,17 +401,22 @@
     tray_action_.ClearObservedStates();
   }
 
+  void SetPrimaryProfileAndWaitUntilReady() {
+    state_controller_->SetPrimaryProfile(&profile_);
+    ready_waiter_.Run();
+  }
+
   // Helper method to move state controller to the specified state.
   // Should be called at the begining of tests, at most once.
   bool InitializeNoteTakingApp(TrayActionState target_state,
                                bool enable_app_launch) {
     app_ = CreateTestNoteTakingApp(kTestAppId);
-    extensions::ExtensionSystem::Get(signin_profile())
+    extensions::ExtensionSystem::Get(lock_screen_profile())
         ->extension_service()
         ->AddExtension(app_.get());
 
     app_manager_->SetInitialAppState(kTestAppId, enable_app_launch);
-    state_controller_->SetPrimaryProfile(&profile_);
+    SetPrimaryProfileAndWaitUntilReady();
 
     if (target_state == TrayActionState::kNotAvailable)
       return true;
@@ -446,7 +450,7 @@
     if (target_state == TrayActionState::kLaunching)
       return true;
 
-    app_window_ = CreateNoteTakingWindow(signin_profile(), app());
+    app_window_ = CreateNoteTakingWindow(lock_screen_profile(), app());
     if (!app_window_->window()) {
       ADD_FAILURE() << "Not allowed to create app window.";
       return false;
@@ -461,7 +465,7 @@
   }
 
   TestingProfile* profile() { return &profile_; }
-  TestingProfile* signin_profile() { return signin_profile_; }
+  TestingProfile* lock_screen_profile() { return lock_screen_profile_; }
 
   session_manager::SessionManager* session_manager() {
     return session_manager_.get();
@@ -484,7 +488,16 @@
   std::unique_ptr<base::test::ScopedCommandLine> command_line_;
   TestingProfileManager profile_manager_;
   TestingProfile profile_;
-  TestingProfile* signin_profile_ = nullptr;
+  TestingProfile* lock_screen_profile_ = nullptr;
+
+  // Run loop used to throttle test until async state controller initialization
+  // is fully complete. The quit closure for this run loop will be passed to
+  // |state_controller_| as the callback to be run when the state controller is
+  // ready for action.
+  // NOTE: Tests should call |state_controller_->SetPrimaryProfile(Profile*)|
+  // before running the loop, as that is the method that starts the state
+  // controller.
+  base::RunLoop ready_waiter_;
 
   std::unique_ptr<session_manager::SessionManager> session_manager_;
 
@@ -522,7 +535,7 @@
 
 TEST_F(LockScreenAppStateTest, SetPrimaryProfile) {
   EXPECT_EQ(TestAppManager::State::kNotInitialized, app_manager()->state());
-  state_controller()->SetPrimaryProfile(profile());
+  SetPrimaryProfileAndWaitUntilReady();
 
   EXPECT_EQ(TestAppManager::State::kStopped, app_manager()->state());
   EXPECT_EQ(TrayActionState::kNotAvailable,
@@ -538,7 +551,7 @@
   EXPECT_EQ(TestAppManager::State::kNotInitialized, app_manager()->state());
 
   app_manager()->SetInitialAppState(kTestAppId, true);
-  state_controller()->SetPrimaryProfile(profile());
+  SetPrimaryProfileAndWaitUntilReady();
 
   ASSERT_EQ(TestAppManager::State::kStarted, app_manager()->state());
 
@@ -550,7 +563,7 @@
 
 TEST_F(LockScreenAppStateTest, SessionLock) {
   app_manager()->SetInitialAppState(kTestAppId, true);
-  state_controller()->SetPrimaryProfile(profile());
+  SetPrimaryProfileAndWaitUntilReady();
   ASSERT_EQ(TestAppManager::State::kStopped, app_manager()->state());
 
   session_manager()->SetSessionState(session_manager::SessionState::LOCKED);
@@ -584,7 +597,7 @@
 }
 
 TEST_F(LockScreenAppStateTest, SessionUnlockedWhileStartingAppManager) {
-  state_controller()->SetPrimaryProfile(profile());
+  SetPrimaryProfileAndWaitUntilReady();
   ASSERT_EQ(TestAppManager::State::kStopped, app_manager()->state());
 
   session_manager()->SetSessionState(session_manager::SessionState::LOCKED);
@@ -612,7 +625,7 @@
 }
 
 TEST_F(LockScreenAppStateTest, AppManagerNoApp) {
-  state_controller()->SetPrimaryProfile(profile());
+  SetPrimaryProfileAndWaitUntilReady();
   ASSERT_EQ(TestAppManager::State::kStopped, app_manager()->state());
 
   session_manager()->SetSessionState(session_manager::SessionState::LOCKED);
@@ -646,7 +659,7 @@
 }
 
 TEST_F(LockScreenAppStateTest, AppAvailabilityChanges) {
-  state_controller()->SetPrimaryProfile(profile());
+  SetPrimaryProfileAndWaitUntilReady();
   ASSERT_EQ(TestAppManager::State::kStopped, app_manager()->state());
 
   app_manager()->SetInitialAppState(kTestAppId, false);
@@ -784,7 +797,7 @@
                                       true /* enable_app_launch */));
 
   std::unique_ptr<TestAppWindow> app_window =
-      CreateNoteTakingWindow(signin_profile(), app());
+      CreateNoteTakingWindow(lock_screen_profile(), app());
   EXPECT_FALSE(app_window->window());
 
   tray_action()->SendNewNoteRequest();
@@ -800,10 +813,11 @@
   EXPECT_FALSE(non_eligible_app_window->window());
 
   EXPECT_FALSE(state_controller()->CreateAppWindowForLockScreenAction(
-      signin_profile(), app(), extensions::api::app_runtime::ACTION_TYPE_NONE,
+      lock_screen_profile(), app(),
+      extensions::api::app_runtime::ACTION_TYPE_NONE,
       base::MakeUnique<ChromeAppDelegate>(true)));
 
-  app_window = CreateNoteTakingWindow(signin_profile(), app());
+  app_window = CreateNoteTakingWindow(lock_screen_profile(), app());
   ASSERT_TRUE(app_window->window());
 
   app_window->Initialize(true /* shown */);
@@ -812,7 +826,7 @@
 
   // Test that second app window cannot be registered.
   std::unique_ptr<TestAppWindow> second_app_window =
-      CreateNoteTakingWindow(signin_profile(), app());
+      CreateNoteTakingWindow(lock_screen_profile(), app());
   EXPECT_FALSE(second_app_window->window());
 
   // Test the app window does not get closed by itself.
@@ -837,7 +851,7 @@
                                       true /* enable_app_launch */));
 
   std::unique_ptr<TestAppWindow> app_window =
-      CreateNoteTakingWindow(signin_profile(), app());
+      CreateNoteTakingWindow(lock_screen_profile(), app());
   ASSERT_TRUE(app_window->window());
   app_window->Initialize(false /* shown */);
 
@@ -862,7 +876,7 @@
   ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kActive,
                                       true /* enable_app_launch */));
 
-  extensions::ExtensionSystem::Get(signin_profile())
+  extensions::ExtensionSystem::Get(lock_screen_profile())
       ->extension_service()
       ->UnloadExtension(app()->id(),
                         extensions::UnloadedExtensionReason::UNINSTALL);
@@ -881,7 +895,7 @@
 
   scoped_refptr<extensions::Extension> secondary_app =
       CreateTestNoteTakingApp(kSecondaryTestAppId);
-  extensions::ExtensionSystem::Get(signin_profile())
+  extensions::ExtensionSystem::Get(lock_screen_profile())
       ->extension_service()
       ->AddExtension(secondary_app.get());
 
@@ -897,13 +911,13 @@
   state_controller()->FlushTrayActionForTesting();
 
   std::unique_ptr<TestAppWindow> app_window =
-      CreateNoteTakingWindow(signin_profile(), app());
+      CreateNoteTakingWindow(lock_screen_profile(), app());
   EXPECT_FALSE(app_window->window());
   ASSERT_EQ(TrayActionState::kLaunching,
             state_controller()->GetLockScreenNoteState());
 
   std::unique_ptr<TestAppWindow> secondary_app_window =
-      CreateNoteTakingWindow(signin_profile(), secondary_app.get());
+      CreateNoteTakingWindow(lock_screen_profile(), secondary_app.get());
   ASSERT_TRUE(secondary_app_window->window());
 
   secondary_app_window->Initialize(true /* shown*/);
@@ -914,7 +928,7 @@
   EXPECT_FALSE(secondary_app_window->closed());
 
   // Uninstall the app and test the secondary app window is closed.
-  extensions::ExtensionSystem::Get(signin_profile())
+  extensions::ExtensionSystem::Get(lock_screen_profile())
       ->extension_service()
       ->UnloadExtension(secondary_app->id(),
                         extensions::UnloadedExtensionReason::UNINSTALL);
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc
index 04a96fb5..1202c44 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc
@@ -64,6 +64,8 @@
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   const user_manager::User* user = NULL;
+  if (chromeos::ProfileHelper::IsLockScreenAppProfile(profile))
+    return nullptr;
   if (!chromeos::ProfileHelper::IsSigninProfile(profile))
     user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
   return new EasyUnlockTpmKeyManager(
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc
index bbd4ca4..f8823ec 100644
--- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc
+++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc
@@ -78,8 +78,10 @@
 KeyedService* OwnerSettingsServiceChromeOSFactory::BuildInstanceFor(
     content::BrowserContext* browser_context) {
   Profile* profile = static_cast<Profile*>(browser_context);
-  if (profile->IsGuestSession() || ProfileHelper::IsSigninProfile(profile))
-    return NULL;
+  if (profile->IsGuestSession() || ProfileHelper::IsSigninProfile(profile) ||
+      ProfileHelper::IsLockScreenAppProfile(profile)) {
+    return nullptr;
+  }
   return new OwnerSettingsServiceChromeOS(
       GetDeviceSettingsService(),
       profile,
diff --git a/chrome/browser/chromeos/policy/login_profile_policy_provider.h b/chrome/browser/chromeos/policy/login_profile_policy_provider.h
index 8098052..e3ad9e5f 100644
--- a/chrome/browser/chromeos/policy/login_profile_policy_provider.h
+++ b/chrome/browser/chromeos/policy/login_profile_policy_provider.h
@@ -13,10 +13,10 @@
 
 namespace policy {
 
-// Policy provider for the login profile. Since the login profile is not
-// associated with any user, it does not receive regular user policy. However,
-// several device policies that control features on the login screen surface as
-// user policies in the login profile.
+// Policy provider for the login/lock screen app profile. Since these profiles
+// are not associated with any user, it does not receive regular user policy.
+// However, several device policies that control features on the login/lock
+// screen surface as user policies in the login and the lock screen app profile.
 class LoginProfilePolicyProvider : public ConfigurationPolicyProvider,
                                    public PolicyService::Observer {
  public:
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
index 6ea318b..f6258fb 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
@@ -60,9 +60,12 @@
 
 KeyedService* UserNetworkConfigurationUpdaterFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
+  // On the login/lock screen only device network policies apply.
   Profile* profile = Profile::FromBrowserContext(context);
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
-    return NULL;  // On the login screen only device network policies apply.
+  if (chromeos::ProfileHelper::IsSigninProfile(profile) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
+    return nullptr;
+  }
 
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
@@ -70,7 +73,7 @@
   // Currently, only the network policy of the primary user is supported. See
   // also http://crbug.com/310685 .
   if (user != user_manager::UserManager::Get()->GetPrimaryUser())
-    return NULL;
+    return nullptr;
 
   ProfilePolicyConnector* profile_connector =
       ProfilePolicyConnectorFactory::GetForBrowserContext(context);
diff --git a/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc b/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
index b0681d7..4a3d4807 100644
--- a/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
@@ -146,13 +146,17 @@
 
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
-  // Don't initialize cloud policy for the signin profile.
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  // Don't initialize cloud policy for the signin  and the lock screen app
+  // profile.
+  if (chromeos::ProfileHelper::IsSigninProfile(profile) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
     return {};
+  }
 
-  // |user| should never be nullptr except for the signin profile. This object
-  // is created as part of the Profile creation, which happens right after
-  // sign-in. The just-signed-in User is the active user during that time.
+  // |user| should never be nullptr except for the signin and lock screen app
+  // profile. This object is created as part of the Profile creation, which
+  // happens right after sign-in. The just-signed-in User is the active user
+  // during that time.
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
   CHECK(user);
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index 5bc7736..bd4bb1b 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -42,6 +42,9 @@
 // As defined in /chromeos/dbus/cryptohome_client.cc.
 static const char kUserIdHashSuffix[] = "-hash";
 
+// The name for the lock screen app profile.
+static const char kLockScreenAppProfile[] = "LockScreenAppsProfile";
+
 bool ShouldAddProfileDirPrefix(const std::string& user_id_hash) {
   // Do not add profile dir prefix for legacy profile dir and test
   // user profile. The reason of not adding prefix for test user profile
@@ -171,6 +174,23 @@
 }
 
 // static
+bool ProfileHelper::IsLockScreenAppProfile(const Profile* profile) {
+  return profile &&
+         profile->GetPath().BaseName().value() == kLockScreenAppProfile;
+}
+
+// static
+base::FilePath ProfileHelper::GetLockScreenAppProfilePath() {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  return profile_manager->user_data_dir().AppendASCII(kLockScreenAppProfile);
+}
+
+// static
+std::string ProfileHelper::GetLockScreenAppProfileName() {
+  return kLockScreenAppProfile;
+}
+
+// static
 bool ProfileHelper::IsOwnerProfile(const Profile* profile) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           chromeos::switches::kStubCrosSettings)) {
@@ -358,8 +378,10 @@
   DCHECK(!content::BrowserThread::IsThreadInitialized(
              content::BrowserThread::UI) ||
          content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  if (ProfileHelper::IsSigninProfile(profile))
-    return NULL;
+  if (ProfileHelper::IsSigninProfile(profile) ||
+      ProfileHelper::IsLockScreenAppProfile(profile)) {
+    return nullptr;
+  }
 
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
diff --git a/chrome/browser/chromeos/profiles/profile_helper.h b/chrome/browser/chromeos/profiles/profile_helper.h
index a71b4b6..2c302ba0 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.h
+++ b/chrome/browser/chromeos/profiles/profile_helper.h
@@ -106,6 +106,19 @@
   // signin Profile.
   static bool IsSigninProfile(const Profile* profile);
 
+  // Returns the path used for the lock screen apps profile - profile used
+  // for launching platform apps that can display windows on top of the lock
+  // screen.
+  static base::FilePath GetLockScreenAppProfilePath();
+
+  // Returns the name used for the lock screen app profile.
+  static std::string GetLockScreenAppProfileName();
+
+  // Returns whether |profile| is the lock screen app profile - the profile used
+  // for launching platform apps that can display a window on top of the lock
+  // screen.
+  static bool IsLockScreenAppProfile(const Profile* profile);
+
   // Returns true when |profile| corresponds to owner's profile.
   static bool IsOwnerProfile(const Profile* profile);
 
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 8d579786..478d000 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -989,7 +989,6 @@
       "//components/chrome_apps",
       "//components/constrained_window",
       "//components/drive",
-      "//components/session_manager/core",
       "//components/user_manager",
       "//remoting/base",
       "//remoting/host",
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index c7aee0a..b89408e 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -64,7 +64,6 @@
 #include "chrome/browser/extensions/updater/chromeos_extension_cache_delegate.h"
 #include "chrome/browser/extensions/updater/extension_cache_impl.h"
 #include "chromeos/chromeos_switches.h"
-#include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user_manager.h"
 #else
 #include "extensions/browser/updater/null_extension_cache.h"
@@ -454,9 +453,8 @@
 bool ChromeExtensionsBrowserClient::IsLockScreenContext(
     content::BrowserContext* context) {
 #if defined(OS_CHROMEOS)
-  return chromeos::ProfileHelper::IsSigninProfile(
-             Profile::FromBrowserContext(context)) &&
-         session_manager::SessionManager::Get()->IsSessionStarted();
+  return chromeos::ProfileHelper::IsLockScreenAppProfile(
+      Profile::FromBrowserContext(context));
 #else
   return false;
 #endif
diff --git a/chrome/browser/extensions/chrome_process_manager_delegate.cc b/chrome/browser/extensions/chrome_process_manager_delegate.cc
index 9e983ef..491892a 100644
--- a/chrome/browser/extensions/chrome_process_manager_delegate.cc
+++ b/chrome/browser/extensions/chrome_process_manager_delegate.cc
@@ -22,9 +22,11 @@
 #include "extensions/browser/process_manager_factory.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/one_shot_event.h"
+#include "extensions/common/permissions/permissions_data.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chromeos/chromeos_switches.h"
 #endif
 
 namespace extensions {
@@ -84,6 +86,14 @@
     // policy.
     return login_screen_apps_list->HasKey(extension.id());
   }
+
+  if (chromeos::ProfileHelper::IsLockScreenAppProfile(profile) &&
+      !profile->IsOffTheRecord()) {
+    return base::CommandLine::ForCurrentProcess()->HasSwitch(
+               chromeos::switches::kEnableLockScreenApps) &&
+           extension.permissions_data()->HasAPIPermission(
+               APIPermission::kLockScreen);
+  }
 #endif
 
   return AreBackgroundPagesAllowedForContext(context);
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index b08bba2..763dbbbc 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -355,19 +355,6 @@
   registrar_.Add(this,
                  chrome::NOTIFICATION_PROFILE_DESTRUCTION_STARTED,
                  content::Source<Profile>(profile_));
-#if defined(OS_CHROMEOS)
-  // Sign in profile extension service should observe session start - when the
-  // session is started, the context's process map should be updated to consider
-  // extension scripts to run in lock screen context (as the sign-in profile
-  // will be used to host lock screen apps from that point).
-  // TODO(tbarzic): Consider introducing a profile dedicated to lock screen apps
-  //     so the process map's 'is lock screen context' flag does not have to be
-  //     changed when the user session starts.
-  if (chromeos::ProfileHelper::IsSigninProfile(profile_)) {
-    registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
-                   content::NotificationService::AllSources());
-  }
-#endif
 
   UpgradeDetector::GetInstance()->AddObserver(this);
 
@@ -465,7 +452,8 @@
   bool load_saved_extensions = true;
   bool load_command_line_extensions = extensions_enabled_;
 #if defined(OS_CHROMEOS)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile_)) {
+  if (chromeos::ProfileHelper::IsSigninProfile(profile_) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile_)) {
     load_saved_extensions = false;
     load_command_line_extensions = false;
   }
@@ -2267,20 +2255,6 @@
       OnProfileDestructionStarted();
       break;
     }
-#if defined(OS_CHROMEOS)
-    case chrome::NOTIFICATION_SESSION_STARTED: {
-      DCHECK(chromeos::ProfileHelper::IsSigninProfile(profile_));
-
-      // When the user session starts, mark the signin context as lock screen
-      // context, as it will be used to host apps on lock screen.
-      extensions::ProcessMap::Get(profile_)->set_is_lock_screen_context(true);
-      BrowserThread::PostTask(
-          BrowserThread::IO, FROM_HERE,
-          base::BindOnce(&extensions::InfoMap::SetIsLockScreenContext,
-                         system_->info_map(), true));
-      break;
-    }
-#endif
 
     default:
       NOTREACHED() << "Unexpected notification type.";
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc
index 251b8a2..455d900 100644
--- a/chrome/browser/extensions/extension_system_impl.cc
+++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -208,8 +208,10 @@
   bool autoupdate_enabled = !profile_->IsGuestSession() &&
                             !profile_->IsSystemProfile();
 #if defined(OS_CHROMEOS)
-  if (!extensions_enabled)
+  if (!extensions_enabled ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile_)) {
     autoupdate_enabled = false;
+  }
 #endif  // defined(OS_CHROMEOS)
   extension_service_.reset(new ExtensionService(
       profile_, base::CommandLine::ForCurrentProcess(),
@@ -232,7 +234,10 @@
     if (mode >= ContentVerifierDelegate::BOOTSTRAP)
       content_verifier_->Start();
     info_map()->SetContentVerifier(content_verifier_.get());
-
+#if defined(OS_CHROMEOS)
+    if (chromeos::ProfileHelper::IsLockScreenAppProfile(profile_))
+      info_map()->SetIsLockScreenContext(true);
+#endif
     management_policy_.reset(new ManagementPolicy);
     RegisterManagementPolicyProviders();
   }
@@ -244,9 +249,12 @@
   bool skip_session_extensions = false;
 #if defined(OS_CHROMEOS)
   // Skip loading session extensions if we are not in a user session or if the
-  // profile is the sign-in profile, which doesn't correspond to a user session.
-  skip_session_extensions = !chromeos::LoginState::Get()->IsUserLoggedIn() ||
-                            chromeos::ProfileHelper::IsSigninProfile(profile_);
+  // profile is the sign-in or lock screen app profile, which don't correspond
+  // to a user session.
+  skip_session_extensions =
+      !chromeos::LoginState::Get()->IsUserLoggedIn() ||
+      chromeos::ProfileHelper::IsSigninProfile(profile_) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile_);
   if (chrome::IsRunningInForcedAppMode()) {
     extension_service_->component_loader()->
         AddDefaultComponentExtensionsForKioskMode(skip_session_extensions);
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 0899036..d14ba61 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -936,9 +936,12 @@
       profile, new ukm::debug::DebugPage(base::Bind(
                    &BindableGetUkmService, weak_ptr_factory_.GetWeakPtr())));
 #if defined(OS_CHROMEOS)
-  // Ignore the signin profile for sync disables / history deletion.
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  // Ignore the signin and lock screen app profile for sync disables / history
+  // deletion.
+  if (chromeos::ProfileHelper::IsSigninProfile(profile) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
     return;
+  }
 #endif
   history::HistoryService* history_service =
       HistoryServiceFactory::GetForProfile(profile,
diff --git a/chrome/browser/policy/profile_policy_connector.cc b/chrome/browser/policy/profile_policy_connector.cc
index a595184..53c85a9 100644
--- a/chrome/browser/policy/profile_policy_connector.cc
+++ b/chrome/browser/policy/profile_policy_connector.cc
@@ -98,11 +98,12 @@
 #if defined(OS_CHROMEOS)
   if (!user) {
     DCHECK(schema_registry);
-    // This case occurs for the signin profile.
+    // This case occurs for the signin and the lock screen app profiles.
     special_user_policy_provider_.reset(
         new LoginProfilePolicyProvider(connector->GetPolicyService()));
   } else {
-    // |user| should never be nullptr except for the signin profile.
+    // |user| should never be nullptr except for the signin and the lock screen
+    // app profile.
     is_primary_user_ =
         user == user_manager::UserManager::Get()->GetPrimaryUser();
     // Note that |DeviceLocalAccountPolicyProvider::Create| returns nullptr when
@@ -179,8 +180,8 @@
     return policy_store_;
 #if defined(OS_CHROMEOS)
   if (special_user_policy_provider_) {
-    // |special_user_policy_provider_| is non-null for device-local accounts and
-    // for the login profile.
+    // |special_user_policy_provider_| is non-null for device-local accounts,
+    // for the login profile, and the lock screen app profile.
     const DeviceCloudPolicyManagerChromeOS* const device_cloud_policy_manager =
         g_browser_process->platform_part()
             ->browser_policy_connector_chromeos()
diff --git a/chrome/browser/policy/profile_policy_connector_factory.cc b/chrome/browser/policy/profile_policy_connector_factory.cc
index 314cae16..a6b7cd2d5 100644
--- a/chrome/browser/policy/profile_policy_connector_factory.cc
+++ b/chrome/browser/policy/profile_policy_connector_factory.cc
@@ -107,7 +107,8 @@
 
 #if defined(OS_CHROMEOS)
   Profile* const profile = Profile::FromBrowserContext(context);
-  if (!chromeos::ProfileHelper::IsSigninProfile(profile)) {
+  if (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
+      !chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
     user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
     CHECK(user);
   }
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 2792fe5..a3d038d 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -436,11 +436,12 @@
                             "profile files to the root directory!";
 
 #if defined(OS_CHROMEOS)
-  if (!chromeos::ProfileHelper::IsSigninProfile(this)) {
+  if (!chromeos::ProfileHelper::IsSigninProfile(this) &&
+      !chromeos::ProfileHelper::IsLockScreenAppProfile(this)) {
     const user_manager::User* user =
         chromeos::ProfileHelper::Get()->GetUserByProfile(this);
     // A |User| instance should always exist for a profile which is not the
-    // initial or the sign-in profile.
+    // initial, the sign-in or the lock screen app profile.
     CHECK(user);
     LOG_IF(FATAL,
            !session_manager::SessionManager::Get()->HasSessionForAccountId(
@@ -694,7 +695,8 @@
   // mark the session as initialized. Need to do this before we restart below
   // so we don't get in a weird state where we restart before the session is
   // marked as initialized and so try to initialize it again.
-  if (!chromeos::ProfileHelper::IsSigninProfile(this)) {
+  if (!chromeos::ProfileHelper::IsSigninProfile(this) &&
+      !chromeos::ProfileHelper::IsLockScreenAppProfile(this)) {
     chromeos::ProfileHelper* profile_helper = chromeos::ProfileHelper::Get();
     user_manager::UserManager::Get()->OnProfileInitialized(
         profile_helper->GetUserByProfile(this));
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index bf0157257..00635b8 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -1211,6 +1211,11 @@
       chromeos::ProfileHelper::IsSigninProfile(profile)) {
     extensions_enabled = true;
   }
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kEnableLockScreenApps) &&
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
+    extensions_enabled = true;
+  }
 #endif
   extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(
       extensions_enabled);
@@ -1609,8 +1614,10 @@
 
 bool ProfileManager::ShouldGoOffTheRecord(Profile* profile) {
 #if defined(OS_CHROMEOS)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (chromeos::ProfileHelper::IsSigninProfile(profile) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
     return true;
+  }
 #endif
   return profile->IsGuestSession() || profile->IsSystemProfile();
 }
diff --git a/chrome/browser/signin/easy_unlock_service_factory.cc b/chrome/browser/signin/easy_unlock_service_factory.cc
index 9c68aed2..5e54ddd 100644
--- a/chrome/browser/signin/easy_unlock_service_factory.cc
+++ b/chrome/browser/signin/easy_unlock_service_factory.cc
@@ -84,6 +84,10 @@
   int manifest_id = 0;
 
 #if defined(OS_CHROMEOS)
+  if (chromeos::ProfileHelper::IsLockScreenAppProfile(
+          Profile::FromBrowserContext(context))) {
+    return nullptr;
+  }
   if (chromeos::ProfileHelper::IsSigninProfile(
           Profile::FromBrowserContext(context))) {
     if (!context->IsOffTheRecord())
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.cc b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
index 8fefedc..842021e0 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
@@ -363,10 +363,13 @@
 #if defined(OS_CHROMEOS)
   user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
-  if (user)
+  if (user) {
     user_manager::UserManager::Get()->ChangeUserChildStatus(user, is_child);
-  else if (!chromeos::ProfileHelper::Get()->IsSigninProfile(profile_))
+  } else if (!chromeos::ProfileHelper::Get()->IsSigninProfile(profile_) &&
+             !chromeos::ProfileHelper::Get()->IsLockScreenAppProfile(
+                 profile_)) {
     LOG(DFATAL) << "User instance not found while setting child account flag.";
+  }
 #endif
 }
 
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
index af15bcc4..f0b07cdc 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
@@ -42,8 +42,10 @@
 std::unique_ptr<KeyedService> AppListSyncableServiceFactory::BuildInstanceFor(
     content::BrowserContext* browser_context) {
   Profile* profile = static_cast<Profile*>(browser_context);
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
-    return NULL;
+  if (chromeos::ProfileHelper::IsSigninProfile(profile) ||
+      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
+    return nullptr;
+  }
   VLOG(1) << "BuildInstanceFor: " << profile->GetDebugName()
           << " (" << profile << ")";
   return base::MakeUnique<AppListSyncableService>(
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index c01cff01..4c5465b 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -637,6 +637,7 @@
     case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED: {
       Profile* profile = content::Details<Profile>(details).ptr();
       if (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
+          !chromeos::ProfileHelper::IsLockScreenAppProfile(profile) &&
           !profile->IsGuestSession() && !profile->IsSupervised()) {
         // Start the error notifier services to show auth/sync notifications.
         SigninErrorNotifierFactory::GetForProfile(profile);