Commit a666b374 authored by Avi Drissman's avatar Avi Drissman Committed by Chromium LUCI CQ

Cache Mac channel information

Soon, with TargetChannel, an instance of Chrome on the disk
might be upgraded to an instance of Chrome of a different
channel. Cache the channel information on startup, so that
even if it's changed, the channel information of the current
running instance is available.

This relands aa20f9b8 with
a fix.

Fixed: 1163159
Change-Id: If1e3da89ff70da765782dd4dbdf0505da67c4e3c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2620839Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Auto-Submit: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842079}
parent 5976b8e3
......@@ -578,6 +578,10 @@ void ChromeMainDelegate::PostEarlyInitialization(bool is_running_tests) {
#if defined(OS_ANDROID)
UmaSessionStats::OnStartup();
#endif
#if defined(OS_MAC)
chrome::CacheChannelInfo();
#endif
}
bool ChromeMainDelegate::ShouldCreateFeatureList() {
......
......@@ -42,6 +42,12 @@ std::string GetChannelName();
version_info::Channel GetChannel();
#if defined(OS_MAC)
// Because the channel information on the Mac is baked into the Info.plist file,
// and that file may change during an update, this function must be called
// early in startup to cache the channel info so that the correct channel info
// can be returned later.
void CacheChannelInfo();
// Maps the name of the channel to version_info::Channel, always returning
// Channel::UNKNOWN for unbranded builds. For branded builds defaults to
// Channel::STABLE, if channel is empty, else matches the name and returns
......
......@@ -7,53 +7,101 @@
#import <Foundation/Foundation.h>
#include "base/mac/bundle_locations.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/strings/sys_string_conversions.h"
#include "build/branding_buildflags.h"
#include "components/version_info/version_info.h"
namespace chrome {
std::string GetChannelName() {
namespace {
std::string ChannelName() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Use the main Chrome application bundle and not the framework bundle.
// Keystone keys don't live in the framework.
NSBundle* bundle = base::mac::OuterBundle();
NSString* channel = [bundle objectForInfoDictionaryKey:@"KSChannelID"];
// Only ever return "", "unknown", "beta", "dev", or "canary" in a branded
// build.
// KSProductID is not set (for stable) or "beta", "dev" or "canary" for
// the intel-only build.
// KSProductID is "arm64" (for stable) or "arm64-beta", "arm64-dev" or
// "arm64-canary" for the arm-only build.
// KSProductID is "universal" (for stable) or "universal-beta",
// "universal-dev" or "universal-canary" for the arm+intel universal binary.
if (![bundle objectForInfoDictionaryKey:@"KSProductID"]) {
// This build is not Keystone-enabled, it can't have a channel.
channel = @"unknown";
} else if (!channel || [channel isEqual:@"arm64"] ||
[channel isEqual:@"universal"]) {
// For the intel stable channel, KSChannelID is not set.
channel = @"";
} else {
if ([channel hasPrefix:@"arm64-"])
channel = [channel substringFromIndex:[@"arm64-" length]];
else if ([channel hasPrefix:@"universal-"])
channel = [channel substringFromIndex:[@"universal-" length]];
if ([channel isEqual:@"beta"] || [channel isEqual:@"dev"] ||
[channel isEqual:@"canary"]) {
// do nothing.
} else {
static const base::NoDestructor<std::string> channel([] {
// Use the main Chrome application bundle and not the framework bundle.
// Keystone keys don't live in the framework.
NSBundle* bundle = base::mac::OuterBundle();
NSString* channel = [bundle objectForInfoDictionaryKey:@"KSChannelID"];
// Only ever return "", "unknown", "beta", "dev", or "canary" in a branded
// build.
// KSProductID is not set (for stable) or "beta", "dev" or "canary" for
// the intel-only build.
// KSProductID is "arm64" (for stable) or "arm64-beta", "arm64-dev" or
// "arm64-canary" for the arm-only build.
// KSProductID is "universal" (for stable) or "universal-beta",
// "universal-dev" or "universal-canary" for the arm+intel universal binary.
if (![bundle objectForInfoDictionaryKey:@"KSProductID"]) {
// This build is not Keystone-enabled, it can't have a channel.
channel = @"unknown";
} else if (!channel || [channel isEqual:@"arm64"] ||
[channel isEqual:@"universal"]) {
// For the intel stable channel, KSChannelID is not set.
channel = @"";
} else {
if ([channel hasPrefix:@"arm64-"])
channel = [channel substringFromIndex:[@"arm64-" length]];
else if ([channel hasPrefix:@"universal-"])
channel = [channel substringFromIndex:[@"universal-" length]];
if ([channel isEqual:@"beta"] || [channel isEqual:@"dev"] ||
[channel isEqual:@"canary"]) {
// Do nothing.
} else {
channel = @"unknown";
}
}
}
return base::SysNSStringToUTF8(channel);
return base::SysNSStringToUTF8(channel);
}());
return *channel;
#else
return std::string();
#endif
}
bool SideBySideCapable() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
static const base::NoDestructor<bool> capable([] {
// Use the main Chrome application bundle and not the framework bundle.
// Keystone keys don't live in the framework.
NSBundle* bundle = base::mac::OuterBundle();
if (![bundle objectForInfoDictionaryKey:@"KSProductID"]) {
// This build is not Keystone-enabled, and without a channel assume it is
// side-by-side capable.
return true;
}
if (GetChannelName().empty()) {
// For the stable channel, GetChannelName() returns the empty string.
// Stable Chromes are what side-by-side capable Chromes are running
// side-by-side *to* and by definition are side-by-side capable.
return true;
}
// If there is a CrProductDirName key, then the user data dir of this
// beta/dev/canary Chrome is separate, and it can run side-by-side to the
// stable Chrome.
return [bundle objectForInfoDictionaryKey:@"CrProductDirName"] != nil;
}());
return *capable;
#else
return true;
#endif
}
} // namespace
void CacheChannelInfo() {
ignore_result(ChannelName());
ignore_result(SideBySideCapable());
}
std::string GetChannelName() {
return ChannelName();
}
version_info::Channel GetChannelByName(const std::string& channel) {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
if (channel.empty())
......@@ -69,34 +117,11 @@ version_info::Channel GetChannelByName(const std::string& channel) {
}
bool IsSideBySideCapable() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Use the main Chrome application bundle and not the framework bundle.
// Keystone keys don't live in the framework.
NSBundle* bundle = base::mac::OuterBundle();
if (![bundle objectForInfoDictionaryKey:@"KSProductID"]) {
// This build is not Keystone-enabled, and without a channel assume it is
// side-by-side capable.
return true;
}
if (GetChannelName().empty()) {
// For the stable channel, GetChannelName() returns the empty string.
// Stable Chromes are what side-by-side capable Chromes are running
// side-by-side *to* and by definition are side-by-side capable.
return true;
}
// If there is a CrProductDirName key, then the user data dir of this
// beta/dev/canary Chrome is separate, and it can run side-by-side to the
// stable Chrome.
return [bundle objectForInfoDictionaryKey:@"CrProductDirName"];
#else
return true;
#endif
return SideBySideCapable();
}
version_info::Channel GetChannel() {
return GetChannelByName(GetChannelName());
return GetChannelByName(ChannelName());
}
} // namespace chrome
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