Packaging Google Chrome breaks auto-updates

michaelherrick
New Contributor III

Hi Everyone,

I've recently packaged Google Chrome as a .pkg, and it deploys and works perfectly except that the automatic updates seem to fail. When I go to Chrome -> About Google Chrome , I get the "Updating Google Chrome" message for a moment then "Update failed (error: 12)". Following Google's instructions for resolving this error produces no results. The only thing that seems to fix it is a clean download and install off the .dmg direct from Google. Has anyone else experienced this before?

Thanks,

-Mike

18 REPLIES 18

mpermann
Valued Contributor II

What are the permissions on the Google Chrome.app that you packaged?

michaelherrick
New Contributor III

Actually, I got frustrated using Composer so I used pkgbuild following these instructions:

https://wiki.afp548.com/index.php/Guidelines_for_Mac_software_packaging#Google_Chrome

alexjdale
Valued Contributor III

I see that same error with pkgbuild and Chrome, for what it's worth. I wasn't able to figure it out, even with permissions modifications after installing.

rtrouton
Release Candidate Programs Tester

I'm going to put in an obligatory plug for AutoPkg, as it can handle building a working Chrome installer package for you:

http://autopkg.github.io/autopkg/

Other approaches for packaging drag-and-drop applications like Chrome include using Packages:

https://derflounder.wordpress.com/2014/05/02/building-simple-packages-with-packages/

I've also built a tool for creating installer packages from drag-and-drop applications:

https://github.com/rtrouton/Simple-Package-Creator

bvrooman
Valued Contributor

I fixed an issue with Chrome not updating by deploying a package along with the app that contains:

/Library/Google/Google Chrome Brand.plist
/Library/Google/GoogleSoftwareUpdate/*
/Library/LaunchAgents/com.google.keystone.agent.plist
/Library/LaunchDaemons/com.google.keystone.daemon.plist

I honestly don't recall what error I was seeing, but it may be worth making sure those files exist on your test machine when you try to update.

RobertHammen
Valued Contributor II

@rtrouton I'm even seeing the same thing with packages built with AutoPkg, so... #ymmv

apizz
Valued Contributor

I just did Normal Snapshot with Composer before installing Chrome, install Chrome, configure settings and set auto-update, set bookmarks, etc. and then take after snapshot. Worked like a charm.

Alternatively, I also tried installing Chrome, configure the settings, auto update, etc. and using the preinstalled software option in Composer and that worked as well.

My 2 cents ...

gregneagle
Valued Contributor

Depending on your POV disabling autoupdates for Chrome might be considered a feature and not a bug.

But what's happening here is that when a pkg installs Chrome it's being written to the /Applications folder with root as the owner of the application bundle. When a normal (non-root) user runs the app, they don't have the rights to modify it.

There are ways to install the Google Updater as root also so it can update Chrome if you want to, but I'd think you'd want your software management system (Casper) to manage your software and its updates...

nkalister
Valued Contributor

from the chrome installer script, I believe this is what Greg was referring to . . .

FixChromePerms () {
    if [ -e "/Applications/Google Chrome.app" ]; then
        chgrp -Rh admin /Applications/Google Chrome.app
        chmod -R "a+rX,ug+w,o-w" /Applications/Google Chrome.app
        find /Applications/Google Chrome.app -type l -exec chmod -h "a+rX,ug+w,o-w" {} +
        OS_VERSION=$(sw_vers -productVersion)
        OS_MAJOR=$(sed -Ene 's/^([0-9]+).*/1/p' <<< ${OS_VERSION})
        OS_MINOR=$(sed -Ene 's/^([0-9]+).([0-9]+).*/2/p' <<< ${OS_VERSION})
        QUARANTINE_ATTR=com.apple.quarantine
        if [ ${OS_MAJOR} -gt 10 ] ||
           ([ ${OS_MAJOR} -eq 10 ] && [ ${OS_MINOR} -ge 6 ]) ; then
          # On 10.6, xattr supports -r for recursive operation.
          xattr -d -r "${QUARANTINE_ATTR}" "${DEST}" >& /dev/null
        else
          # On earlier systems, xattr doesn't support -r, so run xattr via find.
          find "${DEST}" -exec xattr -d "${QUARANTINE_ATTR}" {} + >& /dev/null
        fi
    fi
}

Chris_Hafner
Valued Contributor II

Here's +1 for @rtrouton posted methods. For what it's worth, I use composer and distribute as a .dmg.

milesleacy
Valued Contributor

Hey all,

I used autopkg to create my initial Chrome installer package. I have since used @hjuutilainen 's script to enable Chrome to automatically update.

After running the script, Chrome stopped offering to "set up updates for all users", and was able to successfully run an update check for a time.

Today, I encountered Chrome offering to "set up updates for all users" again. When I loaded the About page in Chrome, it was unable to check for updates, returning error 12. After trying the permissions fix @nkalister quoted above, the update check proceeded, but then returned error 11.

After clicking the button to "set up updates for all users" and authenticating, Chrome was able to update.

So, the question is, what happens when you let Chrome "set up updates for all users"? I captured changes during the process and I'm slogging through the list of changes. I'm wondering if anyone listening has already discovered the answer.

donmontalvo
Esteemed Contributor III

+1 to @milesleacy's position.

Chrome has an embedded copy of Flash, and as everyone knows, Flash is updated every time you sneeze.

So disabling automatic updates to Flash might sound like a good idea.

But the truth is, when your company has it's next security audit and they (hopefully) raise a flag, you're going some 'splaining to do, Lucy.

Diaper policy...enable Chrome updates and keep it enabled. If your company/client tells you to disable, teach them why that's a terrible idea (and not recommended or supported by Google).

Don

--
https://donmontalvo.com

milesleacy
Valued Contributor

@donmontalvo I have Chrome automatically updating.

Adobe Flash Installer is a restricted software item - kill, delete, message "Flash Player is a security and performance risk. If you need to view Flash content, you may use Google Chrome."

Chris_Hafner
Valued Contributor II

@milesleacy What an interesting concept. Something tells me that I won't be able to pull that one off but...

Jeff-JAMF
New Contributor

See Ben Toms latest MacMule post on Google Chrome v50 - some significant OS version requirement changes

GOOGLE CHROME 50 OS REQUIREMENT CHANGES

mbezzo
Contributor III

Looks like there still isn't a solid answer for this? I've got a "normal" package (just places the chrome .app in /Applications) that we push out and it fails to update with error 12. I've ran both of the scripts mentioned here - the first doesn't change anything and hjuutilainen's makes the errors go away, but now chrome reports as being up to date but it isn't. (My package is a few months old so is installing version 45). Any ideas? Testing on 10.11.5 currently, so it's not the v50 OS requirements.

Thanks!

p.s. Anybody found anything like Joe Farage's FirefoxInstall.sh? LOVE that - no packaging, always get the latest version. :)

apizz
Valued Contributor

@mbezzo We ran into this issue, but only when for when we initially packaged Chrome and User preferences into a DMG and set the file to Fill User Templates.

We're getting our 10.11.5 image ready and I've been able to deploy the latest version of Chrome (just the app) to /Applications and then run a one-time startup Python script to enable Auto Updates for all users without issue.

I can't seem to find where I acquired the script originally, but I've included it below.

#!/usr/bin/python
# encoding: utf-8
"""
chrome-enable-autoupdates.py

This script enables system wide automatic updates for Google Chrome.
It should work for Chrome versions 18 and later. No configuration needed
as this is originally intended as a munki postinstall script.

Created by Hannes Juutilainen, hjuutilainen@mac.com

History:

2015-09-25, Niklas Blomdalen - Modifications to include old KeystoneRegistration installation (python version) 2014-11-20, Hannes Juutilainen - Modifications for Chrome 39 2012-08-31, Hannes Juutilainen - Added --force flag to keystoneInstall as suggested by Riley Shott 2012-05-29, Hannes Juutilainen - Added more error checking 2012-05-25, Hannes Juutilainen - Added some error checking in main 2012-05-24, Hannes Juutilainen - First version """ import sys import os import getopt import subprocess import plistlib chromePath = "/Applications/Google Chrome.app" infoPlistPath = os.path.realpath(os.path.join(chromePath, 'Contents/Info.plist')) brandPath = "/Library/Google/Google Chrome Brand.plist" brandKey = "KSBrandID" tagPath = infoPlistPath tagKey = "KSChannelID" versionPath = infoPlistPath versionKey = "KSVersion" class Usage(Exception): def __init__(self, msg): self.msg = msg def chromeIsInstalled(): """Check if Chrome is installed""" if os.path.exists(chromePath): return True else: return False def chromeVersion(): """Returns Chrome version""" infoPlist = plistlib.readPlist(infoPlistPath) bundleShortVersion = infoPlist["CFBundleShortVersionString"] return bundleShortVersion def chromeKSUpdateURL(): """Returns KSUpdateURL from Chrome Info.plist""" infoPlist = plistlib.readPlist(infoPlistPath) KSUpdateURL = infoPlist["KSUpdateURL"] return KSUpdateURL def chromeKSProductID(): """Returns KSProductID from Chrome Info.plist""" infoPlist = plistlib.readPlist(infoPlistPath) KSProductID = infoPlist["KSProductID"] return KSProductID def keystoneRegistrationFrameworkPath(): """Returns KeystoneRegistration.framework path""" keystoneRegistration = os.path.join(chromePath, 'Contents/Versions') keystoneRegistration = os.path.join(keystoneRegistration, chromeVersion()) keystoneRegistration = os.path.join(keystoneRegistration, 'Google Chrome Framework.framework') keystoneRegistration = os.path.join(keystoneRegistration, 'Frameworks/KeystoneRegistration.framework') return keystoneRegistration def keystoneInstall(): """Install the current Keystone""" installScript = os.path.join(keystoneRegistrationFrameworkPath(), 'Resources/ksinstall') if not os.path.exists(installScript): installScript = os.path.join(keystoneRegistrationFrameworkPath(), 'Resources/install.py') keystonePayload = os.path.join(keystoneRegistrationFrameworkPath(), 'Resources/Keystone.tbz') if os.path.exists(installScript) and os.path.exists(keystonePayload): retcode = subprocess.call([installScript, '--install', keystonePayload, '--force']) if retcode == 0: return True else: return False else: print >> sys.stderr, "Error: KeystoneRegistration.framework not found" return False def removeChromeFromKeystone(): """Removes Chrome from Keystone""" ksadmin = "/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin" ksadminProcess = [ ksadmin, '--delete', '--productid', chromeKSProductID()] retcode = subprocess.call(ksadminProcess) if retcode == 0: return True else: return False def registerChromeWithKeystone(): """Registers Chrome with Keystone""" ksadmin = "/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin" if os.path.exists(ksadmin): ksadminProcess = [ksadmin, '--register', '--preserve-tttoken', '--productid', chromeKSProductID(), '--version', chromeVersion(), '--xcpath', chromePath, '--url', chromeKSUpdateURL(), '--tag-path', tagPath, '--tag-key', tagKey, '--brand-path', brandPath, '--brand-key', brandKey, '--version-path', versionPath, '--version-key', versionKey] retcode = subprocess.call(ksadminProcess) if retcode == 0: return True else: return False else: print >> sys.stderr, "Error: %s doesn't exist" % ksadmin return False def main(argv=None): if argv is None: argv = sys.argv try: # Check for root if os.geteuid() != 0: print >> sys.stderr, "This script must be run as root" return 1 if not chromeIsInstalled(): print >> sys.stderr, "Error: Chrome is not installed on this computer" return 1 if keystoneInstall(): print "Keystone installed" else: print >> sys.stderr, "Error: Keystone install failed" return 1 if registerChromeWithKeystone(): print "Registered Chrome with Keystone" return 0 else: print >> sys.stderr, "Error: Failed to register Chrome with Keystone" return 1 except Usage, err: print >>sys.stderr, err.msg print >>sys.stderr, "for help use --help" return 2 if __name__ == "__main__": sys.exit(main())

mbezzo
Contributor III

Thanks @aporlebeke That's the script I'm using where I'm seeing the "Chrome is up to date" when it isn't. So, it fixed one issue but presents another! This is such a pain to test too, because if I create a new package, or say use autopkg, the newly packaged version is completely updated, so can't actually test to see if it does properly update! :)

Thanks,
Matt