Skip to content

Commit

Permalink
Move more Omaha code upstream (part 2/3).
Browse files Browse the repository at this point in the history
This CL moves most of the XML generation code to the public repository
to simplify the internal code base. The tests are also updated to now
test the new fields. The logic of this is also mostly just moved from
the internal repository.

There is also a new test for ensuring that the ID generator is correctly
configured when the class is constructed.

Only a few fields are still read as normal strings going forward from
the internal sub-class, and they are directly read as strings, and then
inserted into the XML structure.

BUG=806040

Change-Id: I40a4dd7d9b5701aec8f578fbde3431aa47b09940
Reviewed-on: https://chromium-review.googlesource.com/912236
Reviewed-by: Joshua Pawlicki <waffles@chromium.org>
Commit-Queue: Tommy Nyquist <nyquist@chromium.org>
Cr-Commit-Position: refs/heads/master@{#536210}
  • Loading branch information
tommynyquist authored and Commit Bot committed Feb 12, 2018
1 parent f88fc79 commit 1079bee
Show file tree
Hide file tree
Showing 4 changed files with 276 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,23 @@
package org.chromium.chrome.browser.omaha;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Xml;

import org.xmlpull.v1.XmlSerializer;

import org.chromium.base.BuildInfo;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.identity.SettingsSecureBasedIdentificationGenerator;
import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
import org.chromium.chrome.browser.init.ProcessInitializationHandler;
import org.chromium.components.signin.AccountManagerFacade;
import org.chromium.components.signin.ChromeSigninController;
import org.chromium.ui.base.DeviceFormFactor;

import java.io.IOException;
import java.io.StringWriter;
Expand All @@ -21,16 +31,23 @@
* Generates XML requests to send to the Omaha server.
*/
public abstract class RequestGenerator {
private static final String TAG = "RequestGenerator";

// The Omaha specs say that new installs should use "-1".
public static final int INSTALL_AGE_IMMEDIATELY_AFTER_INSTALLING = -1;

private static final long MS_PER_DAY = 1000 * 60 * 60 * 24;
private static final String SALT = "omahaSalt";
private static final String URL_OMAHA_SERVER = "https://update.googleapis.com/service/update2";

private final Context mApplicationContext;

@VisibleForTesting
public RequestGenerator(Context context) {
mApplicationContext = context.getApplicationContext();
UniqueIdentificationGeneratorFactory.registerGenerator(
SettingsSecureBasedIdentificationGenerator.GENERATOR_ID,
new SettingsSecureBasedIdentificationGenerator(getContext()), false);
}

/**
Expand Down Expand Up @@ -67,7 +84,7 @@ public String generateXML(String sessionID, String versionName, long installAge,
serializer.attribute(null, "requestid", "{" + data.getRequestID() + "}");
serializer.attribute(null, "sessionid", "{" + sessionID + "}");
serializer.attribute(null, "installsource", data.getInstallSource());
appendExtraAttributes("request", serializer);
serializer.attribute(null, "userid", "{" + getDeviceID() + "}");

// Set up <os platform="android"... />
serializer.startTag(null, "os");
Expand All @@ -86,7 +103,14 @@ public String generateXML(String sessionID, String versionName, long installAge,
serializer.attribute(null, "lang", getLanguage());
serializer.attribute(null, "installage", String.valueOf(installAge));
serializer.attribute(null, "ap", getAdditionalParameters());
appendExtraAttributes("app", serializer);
// <code>_numaccounts</code> is actually number of profiles, which is always one for
// Chrome Android.
serializer.attribute(null, "_numaccounts", "1");
serializer.attribute(null, "_numgoogleaccountsondevice",
String.valueOf(getNumGoogleAccountsOnDevice()));
serializer.attribute(null, "_numsignedin", String.valueOf(getNumSignedIn()));
serializer.attribute(
null, "_dl_mgr_disabled", String.valueOf(getDownloadManagerState()));

if (data.isSendInstallEvent()) {
// Set up <event eventtype="2" eventresult="1" />
Expand Down Expand Up @@ -129,6 +153,11 @@ protected Context getContext() {
return mApplicationContext;
}

@VisibleForTesting
public String getAppId() {
return getLayoutIsTablet() ? getAppIdTablet() : getAppIdHandset();
}

/**
* Returns the current Android language and region code (e.g. en-GB or de-DE).
*
Expand Down Expand Up @@ -158,23 +187,116 @@ public String getAdditionalParameters() {
}

/**
* Appends extra attributes to the XML for the given tag.
* @param tag Tag to add extra attributes to.
* @param serializer Serializer to append the attributes to. Expects the last open tag to be
* the one being appended to.
* Returns the number of accounts on the device, bucketed into:
* 0 accounts, 1 account, or 2+ accounts.
*
* @return Number of accounts on the device, bucketed as above.
*/
protected void appendExtraAttributes(String tag, XmlSerializer serializer) throws IOException {
@VisibleForTesting
public int getNumGoogleAccountsOnDevice() {
// RequestGenerator may be invoked from JobService or AlarmManager (through OmahaService),
// so have to make sure AccountManagerFacade instance is initialized.
ThreadUtils.runOnUiThreadBlocking(
() -> ProcessInitializationHandler.getInstance().initializePreNative());
int numAccounts = 0;
try {
numAccounts = AccountManagerFacade.get().getGoogleAccounts().length;
} catch (Exception e) {
Log.e(TAG, "Can't get number of accounts.", e);
}
switch (numAccounts) {
case 0:
return 0;
case 1:
return 1;
default:
return 2;
}
}

/** Returns the UUID of the Chrome version we're running. */
protected abstract String getAppId();
/**
* Determine number of accounts signed in.
*/
@VisibleForTesting
public int getNumSignedIn() {
// We only have a single account.
return ChromeSigninController.get().isSignedIn() ? 1 : 0;
}

/**
* Returns DownloadManager system service enabled state as
* -1 - manager state unknown
* 0 - manager enabled
* 1 - manager disabled by user
* 2 - manager disabled by unknown source
*/
@VisibleForTesting
public int getDownloadManagerState() {
PackageInfo info;
try {
info = getContext().getPackageManager().getPackageInfo(
"com.android.providers.downloads", 0);
} catch (PackageManager.NameNotFoundException e) {
// DownloadManager Package not found.
return -1;
}
int state = getContext().getPackageManager().getApplicationEnabledSetting(info.packageName);
switch (state) {
case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
// Service enable state is taken directly from the manifest.
if (info.applicationInfo.enabled) {
return 0;
} else {
// Service enable state set to disabled in the manifest.
return 2;
}
case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
return 0;
case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
// Service enable state has been explicitly disabled by the user.
return 1;
case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
// Service enable state has been explicitly disabled. Source unknown.
return 2;
default:
// Illegal value returned by getApplicationEnabledSetting(). Should never happen.
return -1;
}
}

/**
* Return a device-specific ID.
*/
public String getDeviceID() {
return UniqueIdentificationGeneratorFactory
.getInstance(SettingsSecureBasedIdentificationGenerator.GENERATOR_ID)
.getUniqueId(SALT);
}

/**
* Determine whether we're on the phone or the tablet. Extracted to a separate method to
* facilitate testing.
*/
@VisibleForTesting
protected boolean getLayoutIsTablet() {
return DeviceFormFactor.isTablet();
}

/** URL for the Omaha server. */
public String getServerUrl() {
return URL_OMAHA_SERVER;
}

/** Returns the UUID of the Chrome version we're running when the device is a handset. */
protected abstract String getAppIdHandset();

/** Returns the UUID of the Chrome version we're running when the device is a tablet. */
protected abstract String getAppIdTablet();

/** Returns the brand code. If one can't be retrieved, return "". */
protected abstract String getBrand();

/** Returns the current client ID. */
protected abstract String getClient();

/** URL for the Omaha server. */
public abstract String getServerUrl();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.omaha.MockRequestGenerator;
import org.chromium.chrome.test.omaha.MockRequestGenerator.DeviceType;
import org.chromium.chrome.test.omaha.MockRequestGenerator.SignedInStatus;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -83,8 +84,8 @@ private static class MockOmahaDelegate extends OmahaDelegate {

@Override
protected RequestGenerator createRequestGenerator(Context context) {
mMockGenerator = new MockRequestGenerator(
context, mIsOnTablet ? DeviceType.TABLET : DeviceType.HANDSET);
mMockGenerator = new MockRequestGenerator(context,
mIsOnTablet ? DeviceType.TABLET : DeviceType.HANDSET, SignedInStatus.FALSE);
return mMockGenerator;
}

Expand Down
Loading

0 comments on commit 1079bee

Please sign in to comment.