Merge changes I756cb844,I79b63c68 into main
* changes:
Rename TimerFileDescriptor to RealtimeScheduler
Enhance TimerFileDescriptor to schedule multiple tasks
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
index c9694d1..764300c 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
@@ -16,18 +16,10 @@
package com.android.server.net.ct;
-import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DEVICE_OFFLINE;
-import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DOWNLOAD_CANNOT_RESUME;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_HTTP_ERROR;
-import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION;
-import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_TOO_MANY_REDIRECTS;
-import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_UNKNOWN;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_VERSION_ALREADY_EXISTS;
-import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__PENDING_WAITING_FOR_WIFI;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
import android.annotation.RequiresApi;
import android.app.DownloadManager;
@@ -43,13 +35,12 @@
import com.android.server.net.ct.DownloadHelper.DownloadStatus;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.List;
/** Helper class to download certificate transparency log files. */
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@@ -61,9 +52,10 @@
private final DataStore mDataStore;
private final DownloadHelper mDownloadHelper;
private final SignatureVerifier mSignatureVerifier;
- private final CertificateTransparencyInstaller mInstaller;
private final CertificateTransparencyLogger mLogger;
+ private final List<CompatibilityVersion> mCompatVersions = new ArrayList<>();
+
private boolean started = false;
CertificateTransparencyDownloader(
@@ -71,25 +63,27 @@
DataStore dataStore,
DownloadHelper downloadHelper,
SignatureVerifier signatureVerifier,
- CertificateTransparencyInstaller installer,
CertificateTransparencyLogger logger) {
mContext = context;
mSignatureVerifier = signatureVerifier;
mDataStore = dataStore;
mDownloadHelper = downloadHelper;
- mInstaller = installer;
mLogger = logger;
}
+ void addCompatibilityVersion(CompatibilityVersion compatVersion) {
+ mCompatVersions.add(compatVersion);
+ }
+
void start() {
if (started) {
return;
}
- mInstaller.addCompatibilityVersion(Config.COMPATIBILITY_VERSION);
mContext.registerReceiver(
this,
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
Context.RECEIVER_EXPORTED);
+ mDataStore.load();
started = true;
if (Config.DEBUG) {
@@ -102,7 +96,7 @@
return;
}
mContext.unregisterReceiver(this);
- mInstaller.removeCompatibilityVersion(Config.COMPATIBILITY_VERSION);
+ mDataStore.delete();
started = false;
if (Config.DEBUG) {
@@ -111,7 +105,7 @@
}
long startPublicKeyDownload() {
- long downloadId = download(mDataStore.getProperty(Config.PUBLIC_KEY_URL));
+ long downloadId = download(Config.URL_PUBLIC_KEY);
if (downloadId != -1) {
mDataStore.setPropertyLong(Config.PUBLIC_KEY_DOWNLOAD_ID, downloadId);
mDataStore.store();
@@ -119,19 +113,31 @@
return downloadId;
}
- long startMetadataDownload() {
- long downloadId = download(mDataStore.getProperty(Config.METADATA_URL));
+ private long startMetadataDownload(CompatibilityVersion compatVersion) {
+ long downloadId = download(compatVersion.getMetadataUrl());
if (downloadId != -1) {
- mDataStore.setPropertyLong(Config.METADATA_DOWNLOAD_ID, downloadId);
+ mDataStore.setPropertyLong(compatVersion.getMetadataPropertyName(), downloadId);
mDataStore.store();
}
return downloadId;
}
- long startContentDownload() {
- long downloadId = download(mDataStore.getProperty(Config.CONTENT_URL));
+ @VisibleForTesting
+ void startMetadataDownload() {
+ for (CompatibilityVersion compatVersion : mCompatVersions) {
+ if (startMetadataDownload(compatVersion) == -1) {
+ Log.e(TAG, "Metadata download not started for " + compatVersion.getCompatVersion());
+ } else if (Config.DEBUG) {
+ Log.d(TAG, "Metadata download started for " + compatVersion.getCompatVersion());
+ }
+ }
+ }
+
+ @VisibleForTesting
+ long startContentDownload(CompatibilityVersion compatVersion) {
+ long downloadId = download(compatVersion.getContentUrl());
if (downloadId != -1) {
- mDataStore.setPropertyLong(Config.CONTENT_DOWNLOAD_ID, downloadId);
+ mDataStore.setPropertyLong(compatVersion.getContentPropertyName(), downloadId);
mDataStore.store();
}
return downloadId;
@@ -145,25 +151,28 @@
return;
}
- long completedId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
+ long completedId =
+ intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, /* defaultValue= */ -1);
if (completedId == -1) {
Log.e(TAG, "Invalid completed download Id");
return;
}
- if (isPublicKeyDownloadId(completedId)) {
+ if (getPublicKeyDownloadId() == completedId) {
handlePublicKeyDownloadCompleted(completedId);
return;
}
- if (isMetadataDownloadId(completedId)) {
- handleMetadataDownloadCompleted(completedId);
- return;
- }
+ for (CompatibilityVersion compatVersion : mCompatVersions) {
+ if (getMetadataDownloadId(compatVersion) == completedId) {
+ handleMetadataDownloadCompleted(compatVersion, completedId);
+ return;
+ }
- if (isContentDownloadId(completedId)) {
- handleContentDownloadCompleted(completedId);
- return;
+ if (getContentDownloadId(compatVersion) == completedId) {
+ handleContentDownloadCompleted(compatVersion, completedId);
+ return;
+ }
}
Log.i(TAG, "Download id " + completedId + " is not recognized.");
@@ -189,35 +198,33 @@
return;
}
- if (startMetadataDownload() == -1) {
- Log.e(TAG, "Metadata download not started.");
- } else if (Config.DEBUG) {
- Log.d(TAG, "Metadata download started successfully.");
- }
+ startMetadataDownload();
}
- private void handleMetadataDownloadCompleted(long downloadId) {
+ private void handleMetadataDownloadCompleted(
+ CompatibilityVersion compatVersion, long downloadId) {
DownloadStatus status = mDownloadHelper.getDownloadStatus(downloadId);
if (!status.isSuccessful()) {
handleDownloadFailed(status);
return;
}
- if (startContentDownload() == -1) {
- Log.e(TAG, "Content download not started.");
+ if (startContentDownload(compatVersion) == -1) {
+ Log.e(TAG, "Content download failed for" + compatVersion.getCompatVersion());
} else if (Config.DEBUG) {
- Log.d(TAG, "Content download started successfully.");
+ Log.d(TAG, "Content download started for" + compatVersion.getCompatVersion());
}
}
- private void handleContentDownloadCompleted(long downloadId) {
+ private void handleContentDownloadCompleted(
+ CompatibilityVersion compatVersion, long downloadId) {
DownloadStatus status = mDownloadHelper.getDownloadStatus(downloadId);
if (!status.isSuccessful()) {
handleDownloadFailed(status);
return;
}
- Uri contentUri = getContentDownloadUri();
- Uri metadataUri = getMetadataDownloadUri();
+ Uri contentUri = getContentDownloadUri(compatVersion);
+ Uri metadataUri = getMetadataDownloadUri(compatVersion);
if (contentUri == null || metadataUri == null) {
Log.e(TAG, "Invalid URIs");
return;
@@ -234,8 +241,7 @@
mLogger.logCTLogListUpdateFailedEvent(
CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND,
mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0)
- );
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0));
}
} catch (InvalidKeyException e) {
if (updateFailureCount()) {
@@ -243,8 +249,7 @@
mLogger.logCTLogListUpdateFailedEvent(
CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0)
- );
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0));
}
} catch (IOException | GeneralSecurityException e) {
Log.e(TAG, "Could not verify new log list", e);
@@ -258,32 +263,19 @@
mLogger.logCTLogListUpdateFailedEvent(
CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0));
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0));
}
return;
}
- String version = null;
try (InputStream inputStream = mContext.getContentResolver().openInputStream(contentUri)) {
- version =
- new JSONObject(new String(inputStream.readAllBytes(), UTF_8))
- .getString("version");
- } catch (JSONException | IOException e) {
- Log.e(TAG, "Could not extract version from log list", e);
- return;
- }
-
- try (InputStream inputStream = mContext.getContentResolver().openInputStream(contentUri)) {
- success = mInstaller.install(Config.COMPATIBILITY_VERSION, inputStream, version);
+ success = compatVersion.install(inputStream);
} catch (IOException e) {
Log.e(TAG, "Could not install new content", e);
return;
}
if (success) {
- // Update information about the stored version on successful install.
- mDataStore.setProperty(Config.VERSION, version);
-
// Reset the number of consecutive log list failure updates back to zero.
mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* value= */ 0);
mDataStore.store();
@@ -305,42 +297,19 @@
mDataStore.getPropertyInt(
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0);
- // HTTP Error
- if (400 <= status.reason() && status.reason() <= 600) {
+ if (status.isHttpError()) {
mLogger.logCTLogListUpdateFailedEvent(
CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_HTTP_ERROR,
failureCount,
status.reason());
} else {
// TODO(b/384935059): handle blocked domain logging
- mLogger.logCTLogListUpdateFailedEvent(
- downloadStatusToFailureReason(status.reason()), failureCount);
+ mLogger.logCTLogListUpdateFailedEventWithDownloadStatus(
+ status.reason(), failureCount);
}
}
}
- /** Converts DownloadStatus reason into failure reason to log. */
- private int downloadStatusToFailureReason(int downloadStatusReason) {
- switch (downloadStatusReason) {
- case DownloadManager.PAUSED_WAITING_TO_RETRY:
- case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
- return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DEVICE_OFFLINE;
- case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
- case DownloadManager.ERROR_HTTP_DATA_ERROR:
- return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_HTTP_ERROR;
- case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
- return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_TOO_MANY_REDIRECTS;
- case DownloadManager.ERROR_CANNOT_RESUME:
- return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DOWNLOAD_CANNOT_RESUME;
- case DownloadManager.ERROR_INSUFFICIENT_SPACE:
- return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE;
- case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
- return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__PENDING_WAITING_FOR_WIFI;
- default:
- return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_UNKNOWN;
- }
- }
-
/**
* Updates the data store with the current number of consecutive log list update failures.
*
@@ -373,17 +342,19 @@
@VisibleForTesting
long getPublicKeyDownloadId() {
- return mDataStore.getPropertyLong(Config.PUBLIC_KEY_DOWNLOAD_ID, -1);
+ return mDataStore.getPropertyLong(Config.PUBLIC_KEY_DOWNLOAD_ID, /* defaultValue= */ -1);
}
@VisibleForTesting
- long getMetadataDownloadId() {
- return mDataStore.getPropertyLong(Config.METADATA_DOWNLOAD_ID, -1);
+ long getMetadataDownloadId(CompatibilityVersion compatVersion) {
+ return mDataStore.getPropertyLong(
+ compatVersion.getMetadataPropertyName(), /* defaultValue */ -1);
}
@VisibleForTesting
- long getContentDownloadId() {
- return mDataStore.getPropertyLong(Config.CONTENT_DOWNLOAD_ID, -1);
+ long getContentDownloadId(CompatibilityVersion compatVersion) {
+ return mDataStore.getPropertyLong(
+ compatVersion.getContentPropertyName(), /* defaultValue= */ -1);
}
@VisibleForTesting
@@ -393,38 +364,27 @@
@VisibleForTesting
boolean hasMetadataDownloadId() {
- return getMetadataDownloadId() != -1;
+ return mCompatVersions.stream()
+ .map(this::getMetadataDownloadId)
+ .anyMatch(downloadId -> downloadId != -1);
}
@VisibleForTesting
boolean hasContentDownloadId() {
- return getContentDownloadId() != -1;
- }
-
- @VisibleForTesting
- boolean isPublicKeyDownloadId(long downloadId) {
- return getPublicKeyDownloadId() == downloadId;
- }
-
- @VisibleForTesting
- boolean isMetadataDownloadId(long downloadId) {
- return getMetadataDownloadId() == downloadId;
- }
-
- @VisibleForTesting
- boolean isContentDownloadId(long downloadId) {
- return getContentDownloadId() == downloadId;
+ return mCompatVersions.stream()
+ .map(this::getContentDownloadId)
+ .anyMatch(downloadId -> downloadId != -1);
}
private Uri getPublicKeyDownloadUri() {
return mDownloadHelper.getUri(getPublicKeyDownloadId());
}
- private Uri getMetadataDownloadUri() {
- return mDownloadHelper.getUri(getMetadataDownloadId());
+ private Uri getMetadataDownloadUri(CompatibilityVersion compatVersion) {
+ return mDownloadHelper.getUri(getMetadataDownloadId(compatVersion));
}
- private Uri getContentDownloadUri() {
- return mDownloadHelper.getUri(getContentDownloadId());
+ private Uri getContentDownloadUri(CompatibilityVersion compatVersion) {
+ return mDownloadHelper.getUri(getContentDownloadId(compatVersion));
}
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyInstaller.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyInstaller.java
deleted file mode 100644
index 9970667..0000000
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyInstaller.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.net.ct;
-
-import android.util.Log;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-/** Installer of CT log lists. */
-public class CertificateTransparencyInstaller {
-
- private static final String TAG = "CertificateTransparencyInstaller";
-
- private final Map<String, CompatibilityVersion> mCompatVersions = new HashMap<>();
-
- // The CT root directory.
- private final File mRootDirectory;
-
- public CertificateTransparencyInstaller(File rootDirectory) {
- mRootDirectory = rootDirectory;
- }
-
- public CertificateTransparencyInstaller(String rootDirectoryPath) {
- this(new File(rootDirectoryPath));
- }
-
- public CertificateTransparencyInstaller() {
- this(Config.CT_ROOT_DIRECTORY_PATH);
- }
-
- void addCompatibilityVersion(String versionName) {
- removeCompatibilityVersion(versionName);
- CompatibilityVersion newCompatVersion =
- new CompatibilityVersion(new File(mRootDirectory, versionName));
- mCompatVersions.put(versionName, newCompatVersion);
- }
-
- void removeCompatibilityVersion(String versionName) {
- CompatibilityVersion compatVersion = mCompatVersions.remove(versionName);
- if (compatVersion != null && !compatVersion.delete()) {
- Log.w(TAG, "Could not delete compatibility version directory.");
- }
- }
-
- CompatibilityVersion getCompatibilityVersion(String versionName) {
- return mCompatVersions.get(versionName);
- }
-
- /**
- * Install a new log list to use during SCT verification.
- *
- * @param compatibilityVersion the compatibility version of the new log list
- * @param newContent an input stream providing the log list
- * @param version the minor version of the new log list
- * @return true if the log list was installed successfully, false otherwise.
- * @throws IOException if the list cannot be saved in the CT directory.
- */
- public boolean install(String compatibilityVersion, InputStream newContent, String version)
- throws IOException {
- CompatibilityVersion compatVersion = mCompatVersions.get(compatibilityVersion);
- if (compatVersion == null) {
- Log.e(TAG, "No compatibility version for " + compatibilityVersion);
- return false;
- }
- // Ensure root directory exists and is readable.
- DirectoryUtils.makeDir(mRootDirectory);
-
- if (!compatVersion.install(newContent, version)) {
- Log.e(TAG, "Failed to install logs version " + version);
- return false;
- }
- Log.i(TAG, "New logs installed at " + compatVersion.getLogsDir());
- return true;
- }
-}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
index 9c92d14..a8acc60 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
@@ -36,7 +36,7 @@
private static final String UPDATE_CONFIG_PERMISSION = "android.permission.UPDATE_CONFIG";
private final Context mContext;
- private final DataStore mDataStore;
+ private final CompatibilityVersion mCompatVersion;
private final CertificateTransparencyDownloader mCertificateTransparencyDownloader;
private final AlarmManager mAlarmManager;
private final PendingIntent mPendingIntent;
@@ -45,12 +45,16 @@
/** Creates a new {@link CertificateTransparencyJob} object. */
public CertificateTransparencyJob(
- Context context,
- DataStore dataStore,
- CertificateTransparencyDownloader certificateTransparencyDownloader) {
+ Context context, CertificateTransparencyDownloader certificateTransparencyDownloader) {
mContext = context;
- mDataStore = dataStore;
+ mCompatVersion =
+ new CompatibilityVersion(
+ Config.COMPATIBILITY_VERSION,
+ Config.URL_SIGNATURE,
+ Config.URL_LOG_LIST,
+ Config.CT_ROOT_DIRECTORY_PATH);
mCertificateTransparencyDownloader = certificateTransparencyDownloader;
+ mCertificateTransparencyDownloader.addCompatibilityVersion(mCompatVersion);
mAlarmManager = context.getSystemService(AlarmManager.class);
mPendingIntent =
PendingIntent.getBroadcast(
@@ -80,6 +84,7 @@
mContext.unregisterReceiver(this);
mAlarmManager.cancel(mPendingIntent);
mCertificateTransparencyDownloader.stop();
+ mCompatVersion.delete();
mDependenciesReady = false;
if (Config.DEBUG) {
@@ -102,16 +107,10 @@
Log.d(TAG, "Starting CT daily job.");
}
if (!mDependenciesReady) {
- mDataStore.load();
mCertificateTransparencyDownloader.start();
mDependenciesReady = true;
}
- mDataStore.setProperty(Config.CONTENT_URL, Config.URL_LOG_LIST);
- mDataStore.setProperty(Config.METADATA_URL, Config.URL_SIGNATURE);
- mDataStore.setProperty(Config.PUBLIC_KEY_URL, Config.URL_PUBLIC_KEY);
- mDataStore.store();
-
if (mCertificateTransparencyDownloader.startPublicKeyDownload() == -1) {
Log.e(TAG, "Public key download not started.");
} else if (Config.DEBUG) {
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java
index 70fb1ae..913c472 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java
@@ -20,9 +20,17 @@
public interface CertificateTransparencyLogger {
/**
+ * Logs a CTLogListUpdateFailed event to statsd, when failure is provided by DownloadManager.
+ *
+ * @param downloadStatus DownloadManager failure status why the log list wasn't updated
+ * @param failureCount number of consecutive log list update failures
+ */
+ void logCTLogListUpdateFailedEventWithDownloadStatus(int downloadStatus, int failureCount);
+
+ /**
* Logs a CTLogListUpdateFailed event to statsd, when no HTTP error status code is present.
*
- * @param failureReason reason why the log list wasn't updated (e.g. DownloadManager failures)
+ * @param failureReason reason why the log list wasn't updated
* @param failureCount number of consecutive log list update failures
*/
void logCTLogListUpdateFailedEvent(int failureReason, int failureCount);
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java
index f660752..b97a885 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java
@@ -17,11 +17,26 @@
package com.android.server.net.ct;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DEVICE_OFFLINE;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DOWNLOAD_CANNOT_RESUME;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_HTTP_ERROR;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_TOO_MANY_REDIRECTS;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_UNKNOWN;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__PENDING_WAITING_FOR_WIFI;
+
+import android.app.DownloadManager;
/** Implementation for logging to statsd for Certificate Transparency. */
class CertificateTransparencyLoggerImpl implements CertificateTransparencyLogger {
@Override
+ public void logCTLogListUpdateFailedEventWithDownloadStatus(
+ int downloadStatus, int failureCount) {
+ logCTLogListUpdateFailedEvent(downloadStatusToFailureReason(downloadStatus), failureCount);
+ }
+
+ @Override
public void logCTLogListUpdateFailedEvent(int failureReason, int failureCount) {
logCTLogListUpdateFailedEvent(failureReason, failureCount, /* httpErrorStatusCode= */ 0);
}
@@ -37,4 +52,26 @@
);
}
+ /** Converts DownloadStatus reason into failure reason to log. */
+ private int downloadStatusToFailureReason(int downloadStatusReason) {
+ switch (downloadStatusReason) {
+ case DownloadManager.PAUSED_WAITING_TO_RETRY:
+ case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DEVICE_OFFLINE;
+ case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
+ case DownloadManager.ERROR_HTTP_DATA_ERROR:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_HTTP_ERROR;
+ case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_TOO_MANY_REDIRECTS;
+ case DownloadManager.ERROR_CANNOT_RESUME:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_DOWNLOAD_CANNOT_RESUME;
+ case DownloadManager.ERROR_INSUFFICIENT_SPACE:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE;
+ case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__PENDING_WAITING_FOR_WIFI;
+ default:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_UNKNOWN;
+ }
+ }
+
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
index eb24567..ed98056 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
@@ -61,10 +61,8 @@
dataStore,
downloadHelper,
signatureVerifier,
- new CertificateTransparencyInstaller(),
new CertificateTransparencyLoggerImpl());
- mCertificateTransparencyJob =
- new CertificateTransparencyJob(context, dataStore, downloader);
+ mCertificateTransparencyJob = new CertificateTransparencyJob(context, downloader);
}
/**
diff --git a/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java b/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
index 27488b5..fdeb746 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
@@ -15,58 +15,92 @@
*/
package com.android.server.net.ct;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import android.annotation.RequiresApi;
+import android.os.Build;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.Log;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
/** Represents a compatibility version directory. */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
class CompatibilityVersion {
+ private static final String TAG = "CompatibilityVersion";
+
static final String LOGS_DIR_PREFIX = "logs-";
static final String LOGS_LIST_FILE_NAME = "log_list.json";
+ static final String CURRENT_LOGS_DIR_SYMLINK_NAME = "current";
- private static final String CURRENT_LOGS_DIR_SYMLINK_NAME = "current";
+ private final String mCompatVersion;
- private final File mRootDirectory;
+ private final String mMetadataUrl;
+ private final String mContentUrl;
+ private final File mVersionDirectory;
private final File mCurrentLogsDirSymlink;
- private File mCurrentLogsDir = null;
+ CompatibilityVersion(
+ String compatVersion, String metadataUrl, String contentUrl, File rootDirectory) {
+ mCompatVersion = compatVersion;
+ mMetadataUrl = metadataUrl;
+ mContentUrl = contentUrl;
+ mVersionDirectory = new File(rootDirectory, compatVersion);
+ mCurrentLogsDirSymlink = new File(mVersionDirectory, CURRENT_LOGS_DIR_SYMLINK_NAME);
+ }
- CompatibilityVersion(File rootDirectory) {
- mRootDirectory = rootDirectory;
- mCurrentLogsDirSymlink = new File(mRootDirectory, CURRENT_LOGS_DIR_SYMLINK_NAME);
+ CompatibilityVersion(
+ String compatVersion, String metadataUrl, String contentUrl, String rootDirectoryPath) {
+ this(compatVersion, metadataUrl, contentUrl, new File(rootDirectoryPath));
}
/**
* Installs a log list within this compatibility version directory.
*
* @param newContent an input stream providing the log list
- * @param version the version number of the log list
* @return true if the log list was installed successfully, false otherwise.
* @throws IOException if the list cannot be saved in the CT directory.
*/
- boolean install(InputStream newContent, String version) throws IOException {
- // To support atomically replacing the old configuration directory with the new there's a
- // bunch of steps. We create a new directory with the logs and then do an atomic update of
- // the current symlink to point to the new directory.
- // 1. Ensure that the root directory exists and is readable.
- DirectoryUtils.makeDir(mRootDirectory);
+ boolean install(InputStream newContent) throws IOException {
+ String content = new String(newContent.readAllBytes(), UTF_8);
+ try {
+ return install(
+ new ByteArrayInputStream(content.getBytes()),
+ new JSONObject(content).getString("version"));
+ } catch (JSONException e) {
+ Log.e(TAG, "invalid log list format", e);
+ return false;
+ }
+ }
- File newLogsDir = new File(mRootDirectory, LOGS_DIR_PREFIX + version);
+ private boolean install(InputStream newContent, String version) throws IOException {
+ // To support atomically replacing the old configuration directory with the new
+ // there's a bunch of steps. We create a new directory with the logs and then do
+ // an atomic update of the current symlink to point to the new directory.
+ // 1. Ensure the path to the root directory exists and is readable.
+ DirectoryUtils.makeDir(mVersionDirectory);
+
+ File newLogsDir = new File(mVersionDirectory, LOGS_DIR_PREFIX + version);
// 2. Handle the corner case where the new directory already exists.
if (newLogsDir.exists()) {
- // If the symlink has already been updated then the update died between steps 6 and 7
- // and so we cannot delete the directory since it is in use.
+ // If the symlink has already been updated then the update died between steps 6
+ // and 7 and so we cannot delete the directory since it is in use.
if (newLogsDir.getCanonicalPath().equals(mCurrentLogsDirSymlink.getCanonicalPath())) {
+ Log.i(TAG, newLogsDir + " already exists, skipping install.");
deleteOldLogDirectories();
return false;
}
- // If the symlink has not been updated then the previous installation failed and this is
- // a re-attempt. Clean-up leftover files and try again.
+ // If the symlink has not been updated then the previous installation failed and
+ // this is a re-attempt. Clean-up leftover files and try again.
DirectoryUtils.removeDir(newLogsDir);
}
try {
@@ -80,8 +114,8 @@
}
DirectoryUtils.setWorldReadable(logListFile);
- // 5. Create temp symlink. We rename this to the target symlink to get an atomic update.
- File tempSymlink = new File(mRootDirectory, "new_symlink");
+ // 5. Create temp symlink. We rename to the target symlink for an atomic update.
+ File tempSymlink = new File(mVersionDirectory, "new_symlink");
try {
Os.symlink(newLogsDir.getCanonicalPath(), tempSymlink.getCanonicalPath());
} catch (ErrnoException e) {
@@ -95,17 +129,33 @@
throw e;
}
// 7. Cleanup
- mCurrentLogsDir = newLogsDir;
+ Log.i(TAG, "New logs installed at " + newLogsDir);
deleteOldLogDirectories();
return true;
}
- File getRootDir() {
- return mRootDirectory;
+ String getCompatVersion() {
+ return mCompatVersion;
}
- File getLogsDir() {
- return mCurrentLogsDir;
+ String getMetadataUrl() {
+ return mMetadataUrl;
+ }
+
+ String getMetadataPropertyName() {
+ return mCompatVersion + "_" + Config.METADATA_DOWNLOAD_ID;
+ }
+
+ String getContentUrl() {
+ return mContentUrl;
+ }
+
+ String getContentPropertyName() {
+ return mCompatVersion + "_" + Config.CONTENT_DOWNLOAD_ID;
+ }
+
+ File getVersionDir() {
+ return mVersionDirectory;
}
File getLogsDirSymlink() {
@@ -113,19 +163,21 @@
}
File getLogsFile() {
- return new File(mCurrentLogsDir, LOGS_LIST_FILE_NAME);
+ return new File(mCurrentLogsDirSymlink, LOGS_LIST_FILE_NAME);
}
- boolean delete() {
- return DirectoryUtils.removeDir(mRootDirectory);
+ void delete() {
+ if (!DirectoryUtils.removeDir(mVersionDirectory)) {
+ Log.w(TAG, "Could not delete compatibility version directory " + mVersionDirectory);
+ }
}
private void deleteOldLogDirectories() throws IOException {
- if (!mRootDirectory.exists()) {
+ if (!mVersionDirectory.exists()) {
return;
}
File currentTarget = mCurrentLogsDirSymlink.getCanonicalFile();
- for (File file : mRootDirectory.listFiles()) {
+ for (File file : mVersionDirectory.listFiles()) {
if (!currentTarget.equals(file.getCanonicalFile())
&& file.getName().startsWith(LOGS_DIR_PREFIX)) {
DirectoryUtils.removeDir(file);
diff --git a/networksecurity/service/src/com/android/server/net/ct/Config.java b/networksecurity/service/src/com/android/server/net/ct/Config.java
index aafee60..592bc4e 100644
--- a/networksecurity/service/src/com/android/server/net/ct/Config.java
+++ b/networksecurity/service/src/com/android/server/net/ct/Config.java
@@ -48,11 +48,8 @@
// properties
static final String VERSION = "version";
- static final String CONTENT_URL = "content_url";
static final String CONTENT_DOWNLOAD_ID = "content_download_id";
- static final String METADATA_URL = "metadata_url";
static final String METADATA_DOWNLOAD_ID = "metadata_download_id";
- static final String PUBLIC_KEY_URL = "public_key_url";
static final String PUBLIC_KEY_DOWNLOAD_ID = "public_key_download_id";
static final String LOG_LIST_UPDATE_FAILURE_COUNT = "log_list_update_failure_count";
diff --git a/networksecurity/service/src/com/android/server/net/ct/DataStore.java b/networksecurity/service/src/com/android/server/net/ct/DataStore.java
index 3779269..8180316 100644
--- a/networksecurity/service/src/com/android/server/net/ct/DataStore.java
+++ b/networksecurity/service/src/com/android/server/net/ct/DataStore.java
@@ -57,6 +57,11 @@
}
}
+ boolean delete() {
+ clear();
+ return mPropertyFile.delete();
+ }
+
long getPropertyLong(String key, long defaultValue) {
return Optional.ofNullable(getProperty(key)).map(Long::parseLong).orElse(defaultValue);
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java b/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java
index ba42a82..54e277a 100644
--- a/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java
+++ b/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java
@@ -25,7 +25,7 @@
class DirectoryUtils {
static void makeDir(File dir) throws IOException {
- dir.mkdir();
+ dir.mkdirs();
if (!dir.isDirectory()) {
throw new IOException("Unable to make directory " + dir.getCanonicalPath());
}
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
index 25f0dc1..34f8dd1 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.server.net.ct;
-import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_VERSION_ALREADY_EXISTS;
@@ -24,7 +24,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -73,15 +72,14 @@
public class CertificateTransparencyDownloaderTest {
@Mock private DownloadManager mDownloadManager;
- @Mock private CertificateTransparencyInstaller mCertificateTransparencyInstaller;
@Mock private CertificateTransparencyLogger mLogger;
private PrivateKey mPrivateKey;
private PublicKey mPublicKey;
private Context mContext;
- private File mTempFile;
private DataStore mDataStore;
private SignatureVerifier mSignatureVerifier;
+ private CompatibilityVersion mCompatVersion;
private CertificateTransparencyDownloader mCertificateTransparencyDownloader;
private long mNextDownloadId = 666;
@@ -95,8 +93,7 @@
mPublicKey = keyPair.getPublic();
mContext = InstrumentationRegistry.getInstrumentation().getContext();
- mTempFile = File.createTempFile("datastore-test", ".properties");
- mDataStore = new DataStore(mTempFile);
+ mDataStore = new DataStore(File.createTempFile("datastore-test", ".properties"));
mSignatureVerifier = new SignatureVerifier(mContext);
mCertificateTransparencyDownloader =
new CertificateTransparencyDownloader(
@@ -104,56 +101,64 @@
mDataStore,
new DownloadHelper(mDownloadManager),
mSignatureVerifier,
- mCertificateTransparencyInstaller,
mLogger);
+ mCompatVersion =
+ new CompatibilityVersion(
+ /* compatVersion= */ "v666",
+ Config.URL_SIGNATURE,
+ Config.URL_LOG_LIST,
+ mContext.getFilesDir());
- prepareDataStore();
prepareDownloadManager();
+ mCertificateTransparencyDownloader.addCompatibilityVersion(mCompatVersion);
+ mCertificateTransparencyDownloader.start();
}
@After
public void tearDown() {
- mTempFile.delete();
mSignatureVerifier.resetPublicKey();
+ mCertificateTransparencyDownloader.stop();
+ mCompatVersion.delete();
}
@Test
public void testDownloader_startPublicKeyDownload() {
assertThat(mCertificateTransparencyDownloader.hasPublicKeyDownloadId()).isFalse();
+
long downloadId = mCertificateTransparencyDownloader.startPublicKeyDownload();
assertThat(mCertificateTransparencyDownloader.hasPublicKeyDownloadId()).isTrue();
- assertThat(mCertificateTransparencyDownloader.isPublicKeyDownloadId(downloadId)).isTrue();
+ assertThat(mCertificateTransparencyDownloader.getPublicKeyDownloadId())
+ .isEqualTo(downloadId);
}
@Test
public void testDownloader_startMetadataDownload() {
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
- long downloadId = mCertificateTransparencyDownloader.startMetadataDownload();
+
+ mCertificateTransparencyDownloader.startMetadataDownload();
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isTrue();
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(downloadId)).isTrue();
}
@Test
public void testDownloader_startContentDownload() {
assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
- long downloadId = mCertificateTransparencyDownloader.startContentDownload();
+
+ mCertificateTransparencyDownloader.startContentDownload(mCompatVersion);
assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isTrue();
- assertThat(mCertificateTransparencyDownloader.isContentDownloadId(downloadId)).isTrue();
}
@Test
public void testDownloader_publicKeyDownloadSuccess_updatePublicKey_startMetadataDownload()
throws Exception {
- long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
- setSuccessfulDownload(publicKeyId, writePublicKeyToFile(mPublicKey));
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(publicKeyId));
+ mContext, makePublicKeyDownloadCompleteIntent(writePublicKeyToFile(mPublicKey)));
assertThat(mSignatureVerifier.getPublicKey()).hasValue(mPublicKey);
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isTrue();
@@ -163,14 +168,14 @@
public void
testDownloader_publicKeyDownloadSuccess_updatePublicKeyFail_doNotStartMetadataDownload()
throws Exception {
- long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
- setSuccessfulDownload(
- publicKeyId, writeToFile("i_am_not_a_base64_encoded_public_key".getBytes()));
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(publicKeyId));
+ mContext,
+ makePublicKeyDownloadCompleteIntent(
+ writeToFile("i_am_not_a_base64_encoded_public_key".getBytes())));
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
@@ -178,17 +183,15 @@
@Test
public void testDownloader_publicKeyDownloadFail_doNotUpdatePublicKey() throws Exception {
- long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
- setFailedDownload(
- publicKeyId, // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(publicKeyId);
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makePublicKeyDownloadFailedIntent(DownloadManager.ERROR_INSUFFICIENT_SPACE));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makePublicKeyDownloadFailedIntent(DownloadManager.ERROR_HTTP_DATA_ERROR));
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
@@ -196,225 +199,208 @@
@Test
public void testDownloader_publicKeyDownloadFail_failureThresholdExceeded_logsFailure()
- throws Exception {
- long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
+ throws Exception {
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
- setFailedDownload(
- publicKeyId, // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(publicKeyId);
+ mDataStore.setPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makePublicKeyDownloadFailedIntent(DownloadManager.ERROR_INSUFFICIENT_SPACE));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
- verify(mLogger, times(1)).logCTLogListUpdateFailedEvent(
- CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, times(1))
+ .logCTLogListUpdateFailedEventWithDownloadStatus(
+ DownloadManager.ERROR_INSUFFICIENT_SPACE,
+ Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
}
@Test
public void testDownloader_publicKeyDownloadFail_failureThresholdNotMet_doesNotLog()
- throws Exception {
- long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
+ throws Exception {
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
// Set the failure count to well below the threshold
mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
- setFailedDownload(
- publicKeyId, // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(publicKeyId);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makePublicKeyDownloadFailedIntent(DownloadManager.ERROR_HTTP_DATA_ERROR));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(1);
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
+ verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
+ anyInt(), anyInt());
}
@Test
public void testDownloader_metadataDownloadSuccess_startContentDownload() {
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, new File("log_list.sig"));
+ mCertificateTransparencyDownloader.startMetadataDownload();
assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(metadataId));
+ mContext,
+ makeMetadataDownloadCompleteIntent(mCompatVersion, new File("log_list.sig")));
assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isTrue();
}
@Test
public void testDownloader_metadataDownloadFail_doNotStartContentDownload() {
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setFailedDownload(
- metadataId,
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(metadataId);
+ mCertificateTransparencyDownloader.startMetadataDownload();
assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeMetadataDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_INSUFFICIENT_SPACE));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeMetadataDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_HTTP_DATA_ERROR));
assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
}
@Test
public void testDownloader_metadataDownloadFail_failureThresholdExceeded_logsFailure()
- throws Exception {
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ throws Exception {
+ mCertificateTransparencyDownloader.startMetadataDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
- setFailedDownload(
- metadataId,
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(metadataId);
+ mDataStore.setPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeMetadataDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_INSUFFICIENT_SPACE));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
- verify(mLogger, times(1)).logCTLogListUpdateFailedEvent(
- CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, times(1))
+ .logCTLogListUpdateFailedEventWithDownloadStatus(
+ DownloadManager.ERROR_INSUFFICIENT_SPACE,
+ Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
}
@Test
public void testDownloader_metadataDownloadFail_failureThresholdNotMet_doesNotLog()
- throws Exception {
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ throws Exception {
+ mCertificateTransparencyDownloader.startMetadataDownload();
// Set the failure count to well below the threshold
mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
- setFailedDownload(
- metadataId,
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(metadataId);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeMetadataDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_INSUFFICIENT_SPACE));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(1);
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
+ verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
+ anyInt(), anyInt());
}
@Test
- public void testDownloader_contentDownloadSuccess_installSuccess_updateDataStore()
- throws Exception {
+ public void testDownloader_contentDownloadSuccess_installSuccess() throws Exception {
String newVersion = "456";
File logListFile = makeLogListFile(newVersion);
File metadataFile = sign(logListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
- when(mCertificateTransparencyInstaller.install(
- eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
- .thenReturn(true);
+ mCertificateTransparencyDownloader.startMetadataDownload();
assertNoVersionIsInstalled();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
assertInstallSuccessful(newVersion);
}
@Test
public void testDownloader_contentDownloadFail_doNotInstall() throws Exception {
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setFailedDownload(
- contentId,
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(contentId);
+ mCertificateTransparencyDownloader.startContentDownload(mCompatVersion);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeContentDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_INSUFFICIENT_SPACE));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeContentDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_HTTP_DATA_ERROR));
- verify(mCertificateTransparencyInstaller, never()).install(any(), any(), any());
assertNoVersionIsInstalled();
}
@Test
public void testDownloader_contentDownloadFail_failureThresholdExceeded_logsFailure()
- throws Exception {
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
+ throws Exception {
+ mCertificateTransparencyDownloader.startContentDownload(mCompatVersion);
// Set the failure count to just below the threshold
- mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
- setFailedDownload(
- contentId,
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(contentId);
+ mDataStore.setPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeContentDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_INSUFFICIENT_SPACE));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
- verify(mLogger, times(1)).logCTLogListUpdateFailedEvent(
- CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_NO_DISK_SPACE,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, times(1))
+ .logCTLogListUpdateFailedEventWithDownloadStatus(
+ DownloadManager.ERROR_INSUFFICIENT_SPACE,
+ Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
}
@Test
public void testDownloader_contentDownloadFail_failureThresholdNotMet_doesNotLog()
- throws Exception {
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
+ throws Exception {
+ mCertificateTransparencyDownloader.startContentDownload(mCompatVersion);
// Set the failure count to well below the threshold
mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
- setFailedDownload(
- contentId,
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
- Intent downloadCompleteIntent = makeDownloadCompleteIntent(contentId);
- mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makeContentDownloadFailedIntent(
+ mCompatVersion, DownloadManager.ERROR_HTTP_DATA_ERROR));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(1);
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
+ verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
+ anyInt(), anyInt());
}
@Test
- public void testDownloader_contentDownloadSuccess_installFail_doNotUpdateDataStore()
+ public void testDownloader_contentDownloadSuccess_invalidLogList_installFails()
throws Exception {
- File logListFile = makeLogListFile("456");
- File metadataFile = sign(logListFile);
+ File invalidLogListFile = writeToFile("not_a_json_log_list".getBytes());
+ File metadataFile = sign(invalidLogListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
- when(mCertificateTransparencyInstaller.install(
- eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
- .thenReturn(false);
+ mCertificateTransparencyDownloader.startMetadataDownload();
assertNoVersionIsInstalled();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, invalidLogListFile));
assertNoVersionIsInstalled();
}
@@ -426,30 +412,31 @@
File logListFile = makeLogListFile("456");
File metadataFile = sign(logListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
+ mCertificateTransparencyDownloader.startMetadataDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+ mDataStore.setPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
// Set the public key to be missing
mSignatureVerifier.resetPublicKey();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
- verify(mLogger, times(1)).logCTLogListUpdateFailedEvent(
- CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD
- );
- verify(mLogger, never()).logCTLogListUpdateFailedEvent(
- eq(CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION),
- anyInt()
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, times(1))
+ .logCTLogListUpdateFailedEvent(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND,
+ Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEvent(
+ eq(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION),
+ anyInt());
}
@Test
@@ -464,31 +451,31 @@
KeyPairGenerator instance = KeyPairGenerator.getInstance("EC");
mSignatureVerifier.setPublicKey(instance.generateKeyPair().getPublic());
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
-
// Set the failure count to just below the threshold
- mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+ mDataStore.setPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
// Act
+ mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
// Assert
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
- verify(mLogger, never()).logCTLogListUpdateFailedEvent(
- eq(CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND),
- anyInt()
- );
- verify(mLogger, times(1)).logCTLogListUpdateFailedEvent(
- CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEvent(
+ eq(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND),
+ anyInt());
+ verify(mLogger, times(1))
+ .logCTLogListUpdateFailedEvent(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
+ Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
}
@Test
@@ -503,31 +490,31 @@
KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA");
mSignatureVerifier.setPublicKey(instance.generateKeyPair().getPublic());
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
-
// Set the failure count to just below the threshold
- mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+ mDataStore.setPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
// Act
+ mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
// Assert
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
- verify(mLogger, never()).logCTLogListUpdateFailedEvent(
- eq(CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND),
- anyInt()
- );
- verify(mLogger, times(1)).logCTLogListUpdateFailedEvent(
- CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEvent(
+ eq(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND),
+ anyInt());
+ verify(mLogger, times(1))
+ .logCTLogListUpdateFailedEvent(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
+ Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
}
@Test
@@ -536,85 +523,84 @@
throws Exception {
File logListFile = makeLogListFile("456");
File metadataFile = sign(logListFile);
- // Set the public key wrong, so signature verification fails
- mSignatureVerifier.setPublicKey(mPublicKey);
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
+ // Set the key to be deliberately wrong by using diff key pair
+ KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA");
+ mSignatureVerifier.setPublicKey(instance.generateKeyPair().getPublic());
// Set the failure count to well below the threshold
mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
+ mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(1);
- verify(mLogger, never()).logCTLogListUpdateFailedEvent(
- eq(CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND),
- anyInt()
- );
- verify(mLogger, never()).logCTLogListUpdateFailedEvent(
- eq(CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION),
- anyInt()
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(1);
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEvent(
+ eq(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND),
+ anyInt());
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEvent(
+ eq(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION),
+ anyInt());
}
@Test
public void
testDownloader_contentDownloadSuccess_installFail_failureThresholdExceeded_logsFailure()
throws Exception {
- File logListFile = makeLogListFile("456");
- File metadataFile = sign(logListFile);
+ File invalidLogListFile = writeToFile("not_a_json_log_list".getBytes());
+ File metadataFile = sign(invalidLogListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
// Set the failure count to just below the threshold
- mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
- when(mCertificateTransparencyInstaller.install(
- eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
- .thenReturn(false);
+ mDataStore.setPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+ mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, invalidLogListFile));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
- verify(mLogger, times(1)).logCTLogListUpdateFailedEvent(
- CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_VERSION_ALREADY_EXISTS,
- Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD
- );
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+ verify(mLogger, times(1))
+ .logCTLogListUpdateFailedEvent(
+ CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_VERSION_ALREADY_EXISTS,
+ Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
}
@Test
public void
testDownloader_contentDownloadSuccess_installFail_failureThresholdNotMet_doesNotLog()
throws Exception {
- File logListFile = makeLogListFile("456");
- File metadataFile = sign(logListFile);
+ File invalidLogListFile = writeToFile("not_a_json_log_list".getBytes());
+ File metadataFile = sign(invalidLogListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
// Set the failure count to well below the threshold
mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
- when(mCertificateTransparencyInstaller.install(
- eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
- .thenReturn(false);
+ mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, invalidLogListFile));
- assertThat(mDataStore.getPropertyInt(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
- .isEqualTo(1);
+ assertThat(
+ mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
+ .isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
+ verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
+ anyInt(), anyInt());
}
@Test
@@ -623,17 +609,14 @@
File logListFile = makeLogListFile("456");
File metadataFile = File.createTempFile("log_list-wrong_metadata", "sig");
mSignatureVerifier.setPublicKey(mPublicKey);
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
assertNoVersionIsInstalled();
+ mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
- verify(mCertificateTransparencyInstaller, never())
- .install(eq(Config.COMPATIBILITY_VERSION), any(), anyString());
assertNoVersionIsInstalled();
}
@@ -643,17 +626,14 @@
File logListFile = makeLogListFile("456");
File metadataFile = sign(logListFile);
mSignatureVerifier.resetPublicKey();
- long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
- setSuccessfulDownload(metadataId, metadataFile);
- long contentId = mCertificateTransparencyDownloader.startContentDownload();
- setSuccessfulDownload(contentId, logListFile);
assertNoVersionIsInstalled();
+ mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
- verify(mCertificateTransparencyInstaller, never())
- .install(eq(Config.COMPATIBILITY_VERSION), any(), anyString());
assertNoVersionIsInstalled();
}
@@ -667,52 +647,37 @@
assertNoVersionIsInstalled();
// 1. Start download of public key.
- long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
- // 2. On successful public key download, set the key and start the metatadata download.
- setSuccessfulDownload(publicKeyId, publicKeyFile);
-
+ // 2. On successful public key download, set the key and start the metatadata
+ // download.
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(publicKeyId));
+ mContext, makePublicKeyDownloadCompleteIntent(publicKeyFile));
// 3. On successful metadata download, start the content download.
- long metadataId = mCertificateTransparencyDownloader.getMetadataDownloadId();
- setSuccessfulDownload(metadataId, metadataFile);
-
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(metadataId));
+ mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
- // 4. On successful content download, verify the signature and install the new version.
- long contentId = mCertificateTransparencyDownloader.getContentDownloadId();
- setSuccessfulDownload(contentId, logListFile);
- when(mCertificateTransparencyInstaller.install(
- eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
- .thenReturn(true);
-
+ // 4. On successful content download, verify the signature and install the new
+ // version.
mCertificateTransparencyDownloader.onReceive(
- mContext, makeDownloadCompleteIntent(contentId));
+ mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
assertInstallSuccessful(newVersion);
}
private void assertNoVersionIsInstalled() {
- assertThat(mDataStore.getProperty(Config.VERSION)).isNull();
+ assertThat(mCompatVersion.getVersionDir().exists()).isFalse();
}
private void assertInstallSuccessful(String version) {
- assertThat(mDataStore.getProperty(Config.VERSION)).isEqualTo(version);
- }
-
- private Intent makeDownloadCompleteIntent(long downloadId) {
- return new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
- .putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
- }
-
- private void prepareDataStore() {
- mDataStore.load();
- mDataStore.setProperty(Config.CONTENT_URL, Config.URL_LOG_LIST);
- mDataStore.setProperty(Config.METADATA_URL, Config.URL_SIGNATURE);
- mDataStore.setProperty(Config.PUBLIC_KEY_URL, Config.URL_PUBLIC_KEY);
+ File logsDir =
+ new File(
+ mCompatVersion.getVersionDir(),
+ CompatibilityVersion.LOGS_DIR_PREFIX + version);
+ assertThat(logsDir.exists()).isTrue();
+ File logsFile = new File(logsDir, CompatibilityVersion.LOGS_LIST_FILE_NAME);
+ assertThat(logsFile.exists()).isTrue();
}
private void prepareDownloadManager() {
@@ -720,6 +685,32 @@
.thenAnswer(invocation -> mNextDownloadId++);
}
+ private Intent makePublicKeyDownloadCompleteIntent(File publicKeyfile) {
+ return makeDownloadCompleteIntent(
+ mCertificateTransparencyDownloader.getPublicKeyDownloadId(), publicKeyfile);
+ }
+
+ private Intent makeMetadataDownloadCompleteIntent(
+ CompatibilityVersion compatVersion, File signatureFile) {
+ return makeDownloadCompleteIntent(
+ mCertificateTransparencyDownloader.getMetadataDownloadId(compatVersion),
+ signatureFile);
+ }
+
+ private Intent makeContentDownloadCompleteIntent(
+ CompatibilityVersion compatVersion, File logListFile) {
+ return makeDownloadCompleteIntent(
+ mCertificateTransparencyDownloader.getContentDownloadId(compatVersion),
+ logListFile);
+ }
+
+ private Intent makeDownloadCompleteIntent(long downloadId, File file) {
+ when(mDownloadManager.query(any(Query.class))).thenReturn(makeSuccessfulDownloadCursor());
+ when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(Uri.fromFile(file));
+ return new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
+ .putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
+ }
+
private Cursor makeSuccessfulDownloadCursor() {
MatrixCursor cursor =
new MatrixCursor(
@@ -730,9 +721,26 @@
return cursor;
}
- private void setSuccessfulDownload(long downloadId, File file) {
- when(mDownloadManager.query(any(Query.class))).thenReturn(makeSuccessfulDownloadCursor());
- when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(Uri.fromFile(file));
+ private Intent makePublicKeyDownloadFailedIntent(int error) {
+ return makeDownloadFailedIntent(
+ mCertificateTransparencyDownloader.getPublicKeyDownloadId(), error);
+ }
+
+ private Intent makeMetadataDownloadFailedIntent(CompatibilityVersion compatVersion, int error) {
+ return makeDownloadFailedIntent(
+ mCertificateTransparencyDownloader.getMetadataDownloadId(compatVersion), error);
+ }
+
+ private Intent makeContentDownloadFailedIntent(CompatibilityVersion compatVersion, int error) {
+ return makeDownloadFailedIntent(
+ mCertificateTransparencyDownloader.getContentDownloadId(compatVersion), error);
+ }
+
+ private Intent makeDownloadFailedIntent(long downloadId, int error) {
+ when(mDownloadManager.query(any(Query.class))).thenReturn(makeFailedDownloadCursor(error));
+ when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(null);
+ return new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
+ .putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
}
private Cursor makeFailedDownloadCursor(int error) {
@@ -745,16 +753,6 @@
return cursor;
}
- private void setFailedDownload(long downloadId, int... downloadManagerErrors) {
- Cursor first = makeFailedDownloadCursor(downloadManagerErrors[0]);
- Cursor[] others = new Cursor[downloadManagerErrors.length - 1];
- for (int i = 1; i < downloadManagerErrors.length; i++) {
- others[i - 1] = makeFailedDownloadCursor(downloadManagerErrors[i]);
- }
- when(mDownloadManager.query(any())).thenReturn(first, others);
- when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(null);
- }
-
private File writePublicKeyToFile(PublicKey publicKey)
throws IOException, GeneralSecurityException {
return writeToFile(Base64.getEncoder().encode(publicKey.getEncoded()));
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyInstallerTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyInstallerTest.java
deleted file mode 100644
index 50d3f23..0000000
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyInstallerTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.net.ct;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/** Tests for the {@link CertificateTransparencyInstaller}. */
-@RunWith(JUnit4.class)
-public class CertificateTransparencyInstallerTest {
-
- private static final String TEST_VERSION = "test-v1";
-
- private File mTestDir =
- new File(
- InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
- "test-dir");
- private CertificateTransparencyInstaller mCertificateTransparencyInstaller =
- new CertificateTransparencyInstaller(mTestDir);
-
- @Before
- public void setUp() {
- mCertificateTransparencyInstaller.addCompatibilityVersion(TEST_VERSION);
- }
-
- @After
- public void tearDown() {
- mCertificateTransparencyInstaller.removeCompatibilityVersion(TEST_VERSION);
- DirectoryUtils.removeDir(mTestDir);
- }
-
- @Test
- public void testCompatibilityVersion_installSuccessful() throws IOException {
- assertThat(mTestDir.mkdir()).isTrue();
- String content = "i_am_compatible";
- String version = "i_am_version";
- CompatibilityVersion compatVersion =
- mCertificateTransparencyInstaller.getCompatibilityVersion(TEST_VERSION);
-
- try (InputStream inputStream = asStream(content)) {
- assertThat(compatVersion.install(inputStream, version)).isTrue();
- }
- File logsDir = compatVersion.getLogsDir();
- assertThat(logsDir.exists()).isTrue();
- assertThat(logsDir.isDirectory()).isTrue();
- assertThat(logsDir.getAbsolutePath())
- .startsWith(mTestDir.getAbsolutePath() + "/" + TEST_VERSION);
- File logsListFile = compatVersion.getLogsFile();
- assertThat(logsListFile.exists()).isTrue();
- assertThat(logsListFile.getAbsolutePath()).startsWith(logsDir.getAbsolutePath());
- assertThat(readAsString(logsListFile)).isEqualTo(content);
- File logsSymlink = compatVersion.getLogsDirSymlink();
- assertThat(logsSymlink.exists()).isTrue();
- assertThat(logsSymlink.isDirectory()).isTrue();
- assertThat(logsSymlink.getAbsolutePath())
- .startsWith(mTestDir.getAbsolutePath() + "/" + TEST_VERSION + "/current");
- assertThat(logsSymlink.getCanonicalPath()).isEqualTo(logsDir.getCanonicalPath());
-
- assertThat(compatVersion.delete()).isTrue();
- assertThat(logsDir.exists()).isFalse();
- assertThat(logsSymlink.exists()).isFalse();
- assertThat(logsListFile.exists()).isFalse();
- }
-
- @Test
- public void testCompatibilityVersion_versionInstalledFailed() throws IOException {
- assertThat(mTestDir.mkdir()).isTrue();
-
- CompatibilityVersion compatVersion =
- mCertificateTransparencyInstaller.getCompatibilityVersion(TEST_VERSION);
- File rootDir = compatVersion.getRootDir();
- assertThat(rootDir.mkdir()).isTrue();
-
- String existingVersion = "666";
- File existingLogDir =
- new File(rootDir, CompatibilityVersion.LOGS_DIR_PREFIX + existingVersion);
- assertThat(existingLogDir.mkdir()).isTrue();
-
- String existingContent = "somebody_tried_to_install_me_but_failed_halfway_through";
- File logsListFile = new File(existingLogDir, CompatibilityVersion.LOGS_LIST_FILE_NAME);
- assertThat(logsListFile.createNewFile()).isTrue();
- writeToFile(logsListFile, existingContent);
-
- String newContent = "i_am_the_real_content";
- try (InputStream inputStream = asStream(newContent)) {
- assertThat(compatVersion.install(inputStream, existingVersion)).isTrue();
- }
-
- assertThat(readAsString(logsListFile)).isEqualTo(newContent);
- }
-
- @Test
- public void testCertificateTransparencyInstaller_installSuccessfully() throws IOException {
- String content = "i_am_a_certificate_and_i_am_transparent";
- String version = "666";
-
- try (InputStream inputStream = asStream(content)) {
- assertThat(
- mCertificateTransparencyInstaller.install(
- TEST_VERSION, inputStream, version))
- .isTrue();
- }
-
- assertThat(mTestDir.exists()).isTrue();
- assertThat(mTestDir.isDirectory()).isTrue();
- CompatibilityVersion compatVersion =
- mCertificateTransparencyInstaller.getCompatibilityVersion(TEST_VERSION);
- File logsDir = compatVersion.getLogsDir();
- assertThat(logsDir.exists()).isTrue();
- assertThat(logsDir.isDirectory()).isTrue();
- assertThat(logsDir.getAbsolutePath())
- .startsWith(mTestDir.getAbsolutePath() + "/" + TEST_VERSION);
- File logsListFile = compatVersion.getLogsFile();
- assertThat(logsListFile.exists()).isTrue();
- assertThat(logsListFile.getAbsolutePath()).startsWith(logsDir.getAbsolutePath());
- assertThat(readAsString(logsListFile)).isEqualTo(content);
- }
-
- @Test
- public void testCertificateTransparencyInstaller_versionIsAlreadyInstalled()
- throws IOException {
- String existingVersion = "666";
- String existingContent = "i_was_already_installed_successfully";
- CompatibilityVersion compatVersion =
- mCertificateTransparencyInstaller.getCompatibilityVersion(TEST_VERSION);
-
- DirectoryUtils.makeDir(mTestDir);
- try (InputStream inputStream = asStream(existingContent)) {
- assertThat(compatVersion.install(inputStream, existingVersion)).isTrue();
- }
-
- try (InputStream inputStream = asStream("i_will_be_ignored")) {
- assertThat(
- mCertificateTransparencyInstaller.install(
- TEST_VERSION, inputStream, existingVersion))
- .isFalse();
- }
-
- assertThat(readAsString(compatVersion.getLogsFile())).isEqualTo(existingContent);
- }
-
- private static InputStream asStream(String string) throws IOException {
- return new ByteArrayInputStream(string.getBytes());
- }
-
- private static String readAsString(File file) throws IOException {
- return new String(new FileInputStream(file).readAllBytes());
- }
-
- private static void writeToFile(File file, String string) throws IOException {
- try (OutputStream out = new FileOutputStream(file)) {
- out.write(string.getBytes());
- }
- }
-}
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CompatibilityVersionTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CompatibilityVersionTest.java
new file mode 100644
index 0000000..38fff48
--- /dev/null
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CompatibilityVersionTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.net.ct;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/** Tests for the {@link CompatibilityVersion}. */
+@RunWith(JUnit4.class)
+public class CompatibilityVersionTest {
+
+ private static final String TEST_VERSION = "v123";
+
+ private final File mTestDir =
+ InstrumentationRegistry.getInstrumentation().getContext().getFilesDir();
+ private final CompatibilityVersion mCompatVersion =
+ new CompatibilityVersion(
+ TEST_VERSION, Config.URL_SIGNATURE, Config.URL_LOG_LIST, mTestDir);
+
+ @After
+ public void tearDown() {
+ mCompatVersion.delete();
+ }
+
+ @Test
+ public void testCompatibilityVersion_versionDirectory_setupSuccessful() {
+ File versionDir = mCompatVersion.getVersionDir();
+ assertThat(versionDir.exists()).isFalse();
+ assertThat(versionDir.getAbsolutePath()).startsWith(mTestDir.getAbsolutePath());
+ assertThat(versionDir.getAbsolutePath()).endsWith(TEST_VERSION);
+ }
+
+ @Test
+ public void testCompatibilityVersion_symlink_setupSuccessful() {
+ File dirSymlink = mCompatVersion.getLogsDirSymlink();
+ assertThat(dirSymlink.exists()).isFalse();
+ assertThat(dirSymlink.getAbsolutePath())
+ .startsWith(mCompatVersion.getVersionDir().getAbsolutePath());
+ }
+
+ @Test
+ public void testCompatibilityVersion_logsFile_setupSuccessful() {
+ File logsFile = mCompatVersion.getLogsFile();
+ assertThat(logsFile.exists()).isFalse();
+ assertThat(logsFile.getAbsolutePath())
+ .startsWith(mCompatVersion.getLogsDirSymlink().getAbsolutePath());
+ }
+
+ @Test
+ public void testCompatibilityVersion_installSuccessful() throws Exception {
+ String version = "i_am_version";
+ JSONObject logList = makeLogList(version, "i_am_content");
+
+ try (InputStream inputStream = asStream(logList)) {
+ assertThat(mCompatVersion.install(inputStream)).isTrue();
+ }
+
+ File logListFile = mCompatVersion.getLogsFile();
+ assertThat(logListFile.exists()).isTrue();
+ assertThat(logListFile.getCanonicalPath())
+ .isEqualTo(
+ // <path-to-test-files>/v123/logs-i_am_version/log_list.json
+ new File(
+ new File(
+ mCompatVersion.getVersionDir(),
+ CompatibilityVersion.LOGS_DIR_PREFIX + version),
+ CompatibilityVersion.LOGS_LIST_FILE_NAME)
+ .getCanonicalPath());
+ assertThat(logListFile.getAbsolutePath())
+ .isEqualTo(
+ // <path-to-test-files>/v123/current/log_list.json
+ new File(
+ new File(
+ mCompatVersion.getVersionDir(),
+ CompatibilityVersion.CURRENT_LOGS_DIR_SYMLINK_NAME),
+ CompatibilityVersion.LOGS_LIST_FILE_NAME)
+ .getAbsolutePath());
+ }
+
+ @Test
+ public void testCompatibilityVersion_deleteSuccessfully() throws Exception {
+ try (InputStream inputStream = asStream(makeLogList(/* version= */ "123"))) {
+ assertThat(mCompatVersion.install(inputStream)).isTrue();
+ }
+
+ mCompatVersion.delete();
+
+ assertThat(mCompatVersion.getLogsFile().exists()).isFalse();
+ }
+
+ @Test
+ public void testCompatibilityVersion_invalidLogList() throws Exception {
+ try (InputStream inputStream = new ByteArrayInputStream(("not_a_valid_list".getBytes()))) {
+ assertThat(mCompatVersion.install(inputStream)).isFalse();
+ }
+
+ assertThat(mCompatVersion.getLogsFile().exists()).isFalse();
+ }
+
+ @Test
+ public void testCompatibilityVersion_incompleteVersionExists_replacesOldVersion()
+ throws Exception {
+ String existingVersion = "666";
+ File existingLogDir =
+ new File(
+ mCompatVersion.getVersionDir(),
+ CompatibilityVersion.LOGS_DIR_PREFIX + existingVersion);
+ assertThat(existingLogDir.mkdirs()).isTrue();
+ File logsListFile = new File(existingLogDir, CompatibilityVersion.LOGS_LIST_FILE_NAME);
+ assertThat(logsListFile.createNewFile()).isTrue();
+
+ JSONObject newLogList = makeLogList(existingVersion, "i_am_the_real_content");
+ try (InputStream inputStream = asStream(newLogList)) {
+ assertThat(mCompatVersion.install(inputStream)).isTrue();
+ }
+
+ assertThat(readAsString(logsListFile)).isEqualTo(newLogList.toString());
+ }
+
+ @Test
+ public void testCompatibilityVersion_versionAlreadyExists_installFails() throws Exception {
+ String existingVersion = "666";
+ JSONObject existingLogList = makeLogList(existingVersion, "i_was_installed_successfully");
+ try (InputStream inputStream = asStream(existingLogList)) {
+ assertThat(mCompatVersion.install(inputStream)).isTrue();
+ }
+
+ try (InputStream inputStream = asStream(makeLogList(existingVersion, "i_am_ignored"))) {
+ assertThat(mCompatVersion.install(inputStream)).isFalse();
+ }
+
+ assertThat(readAsString(mCompatVersion.getLogsFile()))
+ .isEqualTo(existingLogList.toString());
+ }
+
+ private static InputStream asStream(JSONObject logList) throws IOException {
+ return new ByteArrayInputStream(logList.toString().getBytes());
+ }
+
+ private static JSONObject makeLogList(String version) throws JSONException {
+ return new JSONObject().put("version", version);
+ }
+
+ private static JSONObject makeLogList(String version, String content) throws JSONException {
+ return makeLogList(version).put("content", content);
+ }
+
+ private static String readAsString(File file) throws IOException {
+ try (InputStream in = new FileInputStream(file)) {
+ return new String(in.readAllBytes());
+ }
+ }
+}
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index b4a3b8a..0eab6e7 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -350,7 +350,7 @@
// TODO: remove "apex_available:platform".
apex_available: [
"//apex_available:platform",
- "com.android.btservices",
+ "com.android.bt",
"com.android.tethering",
"com.android.wifi",
],
diff --git a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
index 320622b..dd0665e 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -21,7 +21,6 @@
import android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG
import android.Manifest.permission.WRITE_DEVICE_CONFIG
-import android.content.pm.PackageManager
import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE
import android.content.pm.PackageManager.FEATURE_WIFI
import android.net.ConnectivityManager
@@ -170,8 +169,8 @@
private fun isAutomotiveWithVisibleBackgroundUser(): Boolean {
val packageManager = context.getPackageManager()
val userManager = context.getSystemService(UserManager::class.java)!!
- return (packageManager.hasSystemFeature(FEATURE_AUTOMOTIVE)
- && userManager.isVisibleBackgroundUsersSupported)
+ return (packageManager.hasSystemFeature(FEATURE_AUTOMOTIVE) &&
+ userManager.isVisibleBackgroundUsersSupported)
}
@BeforeClass