Commit 5bbfbae2 authored by jackhou@chromium.org's avatar jackhou@chromium.org

[Mac] Rebuild app shims when they fail to dyload Chrome Framework.

This also changes app_mode_loader to start Chrome with --app-shim-error
only when it was started by Chrome or if it is the app_list shim. When
started by the user, it launches Chrome with --app-id. This simplifies
how Chrome handles --app-shim-error. It does not need to load the
profile or app extension, and rebuilding the shim does not block
launching the app.

BUG=353047

Review URL: https://codereview.chromium.org/265163006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278126 0039d316-1c4b-4281-b951-d872f2087c98
parent 34f1c421
......@@ -20,7 +20,9 @@
#include "base/mac/foundation_util.h"
#include "base/mac/launch_services_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/process/launch.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/common/chrome_switches.h"
#import "chrome/common/mac/app_mode_chrome_locator.h"
#include "chrome/common/mac/app_mode_common.h"
......@@ -67,11 +69,15 @@ int LoadFrameworkAndStart(app_mode::ChromeAppModeInfo* info) {
}
// ** 2: Read information from the Chrome bundle.
base::FilePath executable_path;
base::string16 raw_version_str;
base::FilePath version_path;
base::FilePath framework_shlib_path;
if (!app_mode::GetChromeBundleInfo(cr_bundle_path, &raw_version_str,
&version_path, &framework_shlib_path)) {
if (!app_mode::GetChromeBundleInfo(cr_bundle_path,
&executable_path,
&raw_version_str,
&version_path,
&framework_shlib_path)) {
LOG(FATAL) << "Couldn't ready Chrome bundle info";
}
base::FilePath app_mode_bundle_path =
......@@ -115,28 +121,53 @@ int LoadFrameworkAndStart(app_mode::ChromeAppModeInfo* info) {
LOG(ERROR) << "Couldn't load framework: " << dlerror();
}
if (ChromeAppModeStart) {
if (ChromeAppModeStart)
return ChromeAppModeStart(info);
} else {
LOG(ERROR) << "Loading Chrome failed, launching with command line.";
// Launch Chrome instead and have it update this app_mode_loader bundle.
CommandLine command_line(CommandLine::NO_PROGRAM);
command_line.AppendSwitchPath(app_mode::kAppShimError,
app_mode_bundle_path);
if (!base::mac::OpenApplicationWithPath(
cr_bundle_path, command_line, kLSLaunchDefaults, NULL)) {
LOG(ERROR) << "Could not launch Chrome from: " << cr_bundle_path.value();
return 1;
}
return 0;
LOG(ERROR) << "Loading Chrome failed, launching Chrome with command line";
CommandLine command_line(executable_path);
// The user_data_dir from the plist is actually the app data dir.
command_line.AppendSwitchPath(
switches::kUserDataDir,
info->user_data_dir.DirName().DirName().DirName());
if (CommandLine::ForCurrentProcess()->HasSwitch(
app_mode::kLaunchedByChromeProcessId) ||
info->app_mode_id == app_mode::kAppListModeId) {
// Pass --app-shim-error to have Chrome rebuild this shim.
// If Chrome has rebuilt this shim once already, then rebuilding doesn't fix
// the problem, so don't try again.
if (!CommandLine::ForCurrentProcess()->HasSwitch(
app_mode::kLaunchedAfterRebuild)) {
command_line.AppendSwitchPath(app_mode::kAppShimError,
app_mode_bundle_path);
}
} else {
// If the shim was launched directly (instead of by Chrome), first ask
// Chrome to launch the app. Chrome will launch the shim again, the same
// error will occur and be handled above. This approach allows the app to be
// started without blocking on fixing the shim and guarantees that the
// profile is loaded when Chrome receives --app-shim-error.
command_line.AppendSwitchPath(switches::kProfileDirectory,
info->profile_dir);
command_line.AppendSwitchASCII(switches::kAppId, info->app_mode_id);
}
// Launch the executable directly since base::mac::OpenApplicationWithPath
// uses LSOpenApplication which doesn't pass command line arguments if the
// application is already running.
if (!base::LaunchProcess(command_line, base::LaunchOptions(), NULL)) {
LOG(ERROR) << "Could not launch Chrome: "
<< command_line.GetCommandLineString();
return 1;
}
return 0;
}
} // namespace
__attribute__((visibility("default")))
int main(int argc, char** argv) {
CommandLine::Init(argc, argv);
app_mode::ChromeAppModeInfo info;
// Hard coded info parameters.
......
......@@ -103,6 +103,9 @@ class AppListService {
// Returns a pointer to the platform specific AppListControllerDelegate.
virtual AppListControllerDelegate* GetControllerDelegate() = 0;
// Create a platform-specific shortcut for the app list.
virtual void CreateShortcut() = 0;
protected:
AppListService() {}
virtual ~AppListService() {}
......
......@@ -45,6 +45,8 @@ class AppListServiceDisabled : public AppListService {
return NULL;
}
virtual void CreateShortcut() OVERRIDE {}
virtual gfx::NativeWindow GetAppListWindow() OVERRIDE {
return NULL;
}
......
......@@ -48,6 +48,7 @@ class AppListServiceImpl : public AppListService,
virtual void AutoShowForProfile(Profile* requested_profile) OVERRIDE;
virtual void EnableAppList(Profile* initial_profile,
AppListEnableSource enable_source) OVERRIDE;
virtual void CreateShortcut() OVERRIDE;
protected:
AppListServiceImpl();
......@@ -61,9 +62,6 @@ class AppListServiceImpl : public AppListService,
// list, and records UMA stats delayed from a previous Chrome process.
void PerformStartupChecks(Profile* initial_profile);
// Create a platform-specific shortcut for the app list.
virtual void CreateShortcut();
private:
static void SendAppListStats();
......
......@@ -62,8 +62,6 @@ class AppListServiceMac : public AppListServiceImpl,
virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
virtual AppListControllerDelegate* GetControllerDelegate() OVERRIDE;
virtual Profile* GetCurrentAppListProfile() OVERRIDE;
// AppListServiceImpl overrides:
virtual void CreateShortcut() OVERRIDE;
// AppShimHandler overrides:
......
......@@ -85,6 +85,10 @@
#include "ui/events/x/touch_factory_x11.h"
#endif
#if defined(OS_MACOSX)
#include "chrome/browser/web_applications/web_app_mac.h"
#endif
#if defined(ENABLE_FULL_PRINTING)
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
......@@ -558,6 +562,11 @@ bool StartupBrowserCreator::ProcessCmdLineImpl(
ui::TouchFactory::SetTouchDeviceListFromCommandLine();
#endif
#if defined(OS_MACOSX)
if (web_app::MaybeRebuildShortcut(command_line))
return true;
#endif
if (!process_startup &&
command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
// Only handle --dump-browser-histograms from a rendezvous. In this case, do
......
......@@ -19,7 +19,7 @@ class AppListServiceLinux : public AppListServiceViews,
static AppListServiceLinux* GetInstance();
// AppListServiceImpl overrides:
// AppListService overrides:
virtual void CreateShortcut() OVERRIDE;
// app_list::AppListViewObserver overrides:
......
......@@ -24,8 +24,6 @@ class AppListServiceWin : public AppListServiceViews {
virtual void HandleFirstRun() OVERRIDE;
virtual void Init(Profile* initial_profile) OVERRIDE;
virtual void ShowForProfile(Profile* requested_profile) OVERRIDE;
// AppListServiceImpl overrides:
virtual void CreateShortcut() OVERRIDE;
private:
......
......@@ -44,9 +44,6 @@ using content::BrowserThread;
namespace {
typedef base::Callback<void(const web_app::ShortcutInfo&,
const extensions::FileHandlersInfo&)> InfoCallback;
#if defined(OS_MACOSX)
const int kDesiredSizes[] = {16, 32, 128, 256, 512};
const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
......@@ -107,7 +104,7 @@ void UpdateAllShortcutsForShortcutInfo(
void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
extensions::FileHandlersInfo file_handlers_info,
InfoCallback callback,
web_app::InfoCallback callback,
const gfx::ImageFamily& image_family) {
// If the image failed to load (e.g. if the resource being loaded was empty)
// use the standard application icon.
......@@ -130,6 +127,27 @@ void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
callback.Run(shortcut_info, file_handlers_info);
}
void IgnoreFileHandlersInfo(
const web_app::ShortcutInfoCallback& shortcut_info_callback,
const web_app::ShortcutInfo& shortcut_info,
const extensions::FileHandlersInfo& file_handlers_info) {
shortcut_info_callback.Run(shortcut_info);
}
} // namespace
namespace web_app {
// The following string is used to build the directory name for
// shortcuts to chrome applications (the kind which are installed
// from a CRX). Application shortcuts to URLs use the {host}_{path}
// for the name of this directory. Hosts can't include an underscore.
// By starting this string with an underscore, we ensure that there
// are no naming conflicts.
static const char kCrxAppPrefix[] = "_crx_";
namespace internals {
void GetInfoForApp(const extensions::Extension* extension,
Profile* profile,
const InfoCallback& callback) {
......@@ -185,27 +203,6 @@ void GetInfoForApp(const extensions::Extension* extension,
base::Bind(&OnImageLoaded, shortcut_info, file_handlers_info, callback));
}
void IgnoreFileHandlersInfo(
const web_app::ShortcutInfoCallback& shortcut_info_callback,
const web_app::ShortcutInfo& shortcut_info,
const extensions::FileHandlersInfo& file_handlers_info) {
shortcut_info_callback.Run(shortcut_info);
}
} // namespace
namespace web_app {
// The following string is used to build the directory name for
// shortcuts to chrome applications (the kind which are installed
// from a CRX). Application shortcuts to URLs use the {host}_{path}
// for the name of this directory. Hosts can't include an underscore.
// By starting this string with an underscore, we ensure that there
// are no naming conflicts.
static const char* kCrxAppPrefix = "_crx_";
namespace internals {
base::FilePath GetSanitizedFileName(const base::string16& name) {
#if defined(OS_WIN)
base::string16 file_name = name;
......@@ -286,9 +283,8 @@ ShortcutInfo ShortcutInfoForExtensionAndProfile(
void UpdateShortcutInfoAndIconForApp(const extensions::Extension* extension,
Profile* profile,
const ShortcutInfoCallback& callback) {
GetInfoForApp(extension,
profile,
base::Bind(&IgnoreFileHandlersInfo, callback));
web_app::internals::GetInfoForApp(
extension, profile, base::Bind(&IgnoreFileHandlersInfo, callback));
}
bool ShouldCreateShortcutFor(Profile* profile,
......@@ -383,9 +379,8 @@ void CreateShortcuts(ShortcutCreationReason reason,
if (!ShouldCreateShortcutFor(profile, app))
return;
GetInfoForApp(app,
profile,
base::Bind(&CreateShortcutsWithInfo, reason, locations));
internals::GetInfoForApp(
app, profile, base::Bind(&CreateShortcutsWithInfo, reason, locations));
}
void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app) {
......@@ -405,9 +400,10 @@ void UpdateAllShortcuts(const base::string16& old_app_title,
const extensions::Extension* app) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
GetInfoForApp(app,
profile,
base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
internals::GetInfoForApp(
app,
profile,
base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
}
bool IsValidUrl(const GURL& url) {
......
......@@ -96,6 +96,11 @@ enum ShortcutCreationReason {
SHORTCUT_CREATION_AUTOMATED,
};
// Called by GetInfoForApp after fetching the ShortcutInfo and FileHandlersInfo.
typedef base::Callback<void(const ShortcutInfo&,
const extensions::FileHandlersInfo&)> InfoCallback;
// Called by UpdateShortcutInfoAndIconForApp after loading the icon.
typedef base::Callback<void(const ShortcutInfo&)> ShortcutInfoCallback;
// Extracts shortcut info of the given WebContents.
......@@ -197,6 +202,11 @@ std::string GetWMClassFromAppName(std::string app_name);
namespace internals {
// Loads relevant info structs for the app and calls |callback|.
void GetInfoForApp(const extensions::Extension* extension,
Profile* profile,
const InfoCallback& callback);
#if defined(OS_WIN)
// Returns the Windows user-level shortcut paths that are specified in
// |creation_locations|.
......
......@@ -14,6 +14,10 @@
#include "chrome/browser/web_applications/web_app.h"
#include "extensions/common/manifest_handlers/file_handler_info.h"
namespace base {
class CommandLine;
}
// Whether to enable update and launch of app shims in tests. (Normally shims
// are never created or launched in tests). Note that update only creates
// internal shim bundles, i.e. it does not create new shims in ~/Applications.
......@@ -28,6 +32,9 @@ base::FilePath GetAppInstallPath(const ShortcutInfo& shortcut_info);
// If necessary, launch the shortcut for an app.
void MaybeLaunchShortcut(const ShortcutInfo& shortcut_info);
// Rebuild the shortcut and relaunch it.
bool MaybeRebuildShortcut(const base::CommandLine& command_line);
// Creates a shortcut for a web application. The shortcut is a stub app
// that simply loads the browser framework and runs the given app.
class WebAppShortcutCreator {
......
......@@ -20,14 +20,17 @@
#include "base/process/process_handle.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#import "chrome/browser/mac/dock.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/ui/app_list/app_list_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
......@@ -214,8 +217,8 @@ bool HasSameUserDataDir(const base::FilePath& bundle_path) {
true /* case_sensitive */);
}
void LaunchShimOnFileThread(
const web_app::ShortcutInfo& shortcut_info) {
void LaunchShimOnFileThread(const web_app::ShortcutInfo& shortcut_info,
bool launched_after_rebuild) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
base::FilePath shim_path = web_app::GetAppInstallPath(shortcut_info);
......@@ -236,6 +239,8 @@ void LaunchShimOnFileThread(
command_line.AppendSwitchASCII(
app_mode::kLaunchedByChromeProcessId,
base::IntToString(base::GetCurrentProcId()));
if (launched_after_rebuild)
command_line.AppendSwitch(app_mode::kLaunchedAfterRebuild);
// Launch without activating (kLSLaunchDontSwitch).
base::mac::OpenApplicationWithPath(
shim_path, command_line, kLSLaunchDefaults | kLSLaunchDontSwitch, NULL);
......@@ -246,6 +251,53 @@ base::FilePath GetAppLoaderPath() {
base::mac::NSToCFCast(@"app_mode_loader.app"));
}
void UpdateAndLaunchShimOnFileThread(
const web_app::ShortcutInfo& shortcut_info,
const extensions::FileHandlersInfo& file_handlers_info) {
base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
shortcut_info.profile_path, shortcut_info.extension_id, GURL());
web_app::internals::UpdatePlatformShortcuts(
shortcut_data_dir, base::string16(), shortcut_info, file_handlers_info);
LaunchShimOnFileThread(shortcut_info, true);
}
void UpdateAndLaunchShim(
const web_app::ShortcutInfo& shortcut_info,
const extensions::FileHandlersInfo& file_handlers_info) {
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(
&UpdateAndLaunchShimOnFileThread, shortcut_info, file_handlers_info));
}
void RebuildAppAndLaunch(const web_app::ShortcutInfo& shortcut_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (shortcut_info.extension_id == app_mode::kAppListModeId) {
AppListService* app_list_service =
AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE);
app_list_service->CreateShortcut();
app_list_service->Show();
return;
}
ProfileManager* profile_manager = g_browser_process->profile_manager();
Profile* profile =
profile_manager->GetProfileByPath(shortcut_info.profile_path);
if (!profile || !profile_manager->IsValidProfile(profile))
return;
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile);
const extensions::Extension* extension = registry->GetExtensionById(
shortcut_info.extension_id, extensions::ExtensionRegistry::ENABLED);
if (!extension || !extension->is_platform_app())
return;
web_app::internals::GetInfoForApp(
extension, profile, base::Bind(&UpdateAndLaunchShim));
}
base::FilePath GetLocalizableAppShortcutsSubdirName() {
static const char kChromiumAppDirName[] = "Chromium Apps.localized";
static const char kChromeAppDirName[] = "Chrome Apps.localized";
......@@ -875,8 +927,22 @@ void MaybeLaunchShortcut(const ShortcutInfo& shortcut_info) {
}
content::BrowserThread::PostTask(
content::BrowserThread::FILE, FROM_HERE,
base::Bind(&LaunchShimOnFileThread, shortcut_info));
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(&LaunchShimOnFileThread, shortcut_info, false));
}
bool MaybeRebuildShortcut(const CommandLine& command_line) {
if (!command_line.HasSwitch(app_mode::kAppShimError))
return false;
base::PostTaskAndReplyWithResult(
content::BrowserThread::GetBlockingPool(),
FROM_HERE,
base::Bind(&BuildShortcutInfoFromBundle,
command_line.GetSwitchValuePath(app_mode::kAppShimError)),
base::Bind(&RebuildAppAndLaunch));
return true;
}
// Called when the app's ShortcutInfo (with icon) is loaded when creating app
......
......@@ -286,7 +286,10 @@
'target_name': 'app_mode_app',
'type': 'executable',
'mac_bundle' : 1,
'variables': { 'enable_wexit_time_destructors': 1, },
'variables': {
'enable_wexit_time_destructors': 1,
'mac_real_dsym': 1,
},
'product_name': 'app_mode_loader',
'dependencies': [
'app_mode_app_support',
......
......@@ -22,12 +22,14 @@ namespace app_mode {
bool FindBundleById(NSString* bundle_id, base::FilePath* out_bundle);
// Given the path to the Chrome bundle, read the following information:
// |executable_path| - Path to the Chrome executable.
// |raw_version_str| - Chrome version.
// |version_path| - |chrome_bundle|/Contents/Versions/|raw_version_str|/
// |framework_shlib_path| - Path to the chrome framework's shared library (not
// the framework directory).
// Returns true if all information read succesfuly, false otherwise.
bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
base::FilePath* executable_path,
base::string16* raw_version_str,
base::FilePath* version_path,
base::FilePath* framework_shlib_path);
......
......@@ -25,6 +25,7 @@ bool FindBundleById(NSString* bundle_id, base::FilePath* out_bundle) {
}
bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
base::FilePath* executable_path,
base::string16* raw_version_str,
base::FilePath* version_path,
base::FilePath* framework_shlib_path) {
......@@ -57,19 +58,25 @@ bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
NSString* cr_bundle_exe =
ObjCCast<NSString>(
[cr_bundle objectForInfoDictionaryKey:@"CFBundleExecutable"]);
// Essentially we want chrome::kFrameworkName which looks like
// "$PRODUCT_STRING Framework.framework". The library itself is at
// "$PRODUCT_STRING Framework.framework/$PRODUCT_STRING Framework". Note that
// $PRODUCT_STRING is not |cr_bundle_exe| because in Canary the framework is
// still called "Google Chrome Framework".
// However, we want the shims to be agnostic to distribution and operate based
// on the data in their plist, so encode the framework names here.
NSDictionary* framework_for_exe = @{
@"Chromium": @"Chromium",
@"Google Chrome": @"Google Chrome",
@"Google Chrome Canary": @"Google Chrome",
};
NSString* framework_name = [framework_for_exe objectForKey:cr_bundle_exe];
NSString* cr_framework_shlib_path =
[cr_versioned_path stringByAppendingPathComponent:
base::SysUTF8ToNSString(chrome::kFrameworkName)];
// chrome::kFrameworkName looks like "$PRODUCT_STRING Framework.framework".
// The library itself is at
// "$PRODUCT_STRING Framework.framework/$PRODUCT_STRING Framework", so we cut
// off the .framework extension here and append it to the path.
// It's important to build the path to the framework this way because
// in Canary the framework is still called "Google Chrome Framework".
[framework_name stringByAppendingString:@" Framework.framework"]];
cr_framework_shlib_path =
[cr_framework_shlib_path stringByAppendingPathComponent:
[base::SysUTF8ToNSString(chrome::kFrameworkName)
stringByDeletingPathExtension]];
[framework_name stringByAppendingString:@" Framework"]];
if (!cr_bundle_exe || !cr_framework_shlib_path)
return false;
......@@ -82,6 +89,7 @@ bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
return false;
// Everything OK, copy output parameters.
*executable_path = base::mac::NSStringToFilePath([cr_bundle executablePath]);
*raw_version_str = base::SysNSStringToUTF16(cr_version);
*version_path = base::mac::NSStringToFilePath(cr_versioned_path);
*framework_shlib_path =
......
......@@ -43,11 +43,12 @@ TEST(ChromeLocatorTest, GetNonExistentBundleInfo) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath executable_path;
base::string16 raw_version;
base::FilePath version_path;
base::FilePath framework_path;
EXPECT_FALSE(app_mode::GetChromeBundleInfo(temp_dir.path(),
&raw_version, &version_path, &framework_path));
&executable_path, &raw_version, &version_path, &framework_path));
}
TEST(ChromeLocatorTest, GetChromeBundleInfo) {
......@@ -57,11 +58,13 @@ TEST(ChromeLocatorTest, GetChromeBundleInfo) {
GetChromeBundlePath(&chrome_bundle_path);
ASSERT_TRUE(base::DirectoryExists(chrome_bundle_path));
base::FilePath executable_path;
base::string16 raw_version;
base::FilePath version_path;
base::FilePath framework_path;
EXPECT_TRUE(GetChromeBundleInfo(chrome_bundle_path,
&raw_version, &version_path, &framework_path));
&executable_path, &raw_version, &version_path, &framework_path));
EXPECT_TRUE(base::PathExists(executable_path));
EXPECT_GT(raw_version.size(), 0U);
EXPECT_TRUE(base::DirectoryExists(version_path));
EXPECT_TRUE(base::PathExists(framework_path));
......
......@@ -41,6 +41,10 @@ extern const char kLaunchedByChromeProcessId[];
// launch Chrome.
extern const char kLaunchedForTest[];
// Indicates to the shim that this Chrome has rebuilt it once already, i.e. if
// it fails to launch again, don't trigger another rebuild.
extern const char kLaunchedAfterRebuild[];
// Path to an app shim bundle. Indicates to Chrome that this shim attempted to
// launch but failed.
extern const char kAppShimError[];
......@@ -98,7 +102,7 @@ extern NSString* const kShortcutBrowserBundleIDPlaceholder;
// Current major/minor version numbers of |ChromeAppModeInfo| (defined below).
const unsigned kCurrentChromeAppModeInfoMajorVersion = 1;
const unsigned kCurrentChromeAppModeInfoMinorVersion = 1;
const unsigned kCurrentChromeAppModeInfoMinorVersion = 2;
// The structure used to pass information from the app mode loader to the
// (browser) framework. This is versioned using major and minor version numbers,
......
......@@ -15,6 +15,7 @@ const char kAppListModeId[] = "app_list";
const char kLaunchedByChromeProcessId[] = "launched-by-chrome-process-id";
const char kLaunchedForTest[] = "launched-for-test";
const char kLaunchedAfterRebuild[] = "launched-after-rebuild";
const char kAppShimError[] = "app-shim-error";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment