Snap for 10447354 from 1acfbef7cc521db4558145f893fa5763a9e1bbaa to mainline-wifi-release

Change-Id: Id65f8076916654d46c5da4c00143387d011da9e5
diff --git a/apex/com.android.geotz/Android.bp b/apex/com.android.geotz/Android.bp
index f4e9bbc..2f85269 100644
--- a/apex/com.android.geotz/Android.bp
+++ b/apex/com.android.geotz/Android.bp
@@ -72,6 +72,9 @@
     srcs: [
         "src/main/java/**/*.java",
     ],
+    libs: [
+        "androidx.annotation_annotation",
+    ],
     static_libs: [
         "offlinelocationtimezoneprovider",
     ],
diff --git a/apex/com.android.geotz/resources/offlineltzprovider.properties b/apex/com.android.geotz/resources/offlineltzprovider.properties
index f5a9f4b..cdb07b9 100644
--- a/apex/com.android.geotz/resources/offlineltzprovider.properties
+++ b/apex/com.android.geotz/resources/offlineltzprovider.properties
@@ -2,6 +2,8 @@
 # com.android.timezone.location.provider.OfflineLocationTimeZoneProviderService
 # deployed in the com.android.geotz mainline module.
 
+# The implementation of com.android.timezone.location.provider.GeoDataFileManager to use.
+geodata.file_manager_impl=com.android.geotz.apex.GeoDataFileManagerImpl
 # The location of the tzs2.dat file to use for time zone boundaries.
 geodata.path=/apex/com.android.geotz/etc/tzs2.dat
 
@@ -11,8 +13,8 @@
 deviceconfig.namespace=system_time
 
 # The prefix that should be applied to keys passed to android.provider.DeviceConfig.
-deviceconfig.key_prefix=geotz_
+deviceconfig.key_prefix=geotz_apex_
 
 # The implementation of com.android.timezone.location.provider.core.MetricsReporter to use.
 # This implementation uses Google's standard metrics reporting.
-metrics_reporter.impl=com.android.geotz.MetricsReporterImpl
\ No newline at end of file
+metrics_reporter.impl=com.android.geotz.apex.MetricsReporterImpl
diff --git a/apex/com.android.geotz/src/main/java/com/android/geotz/apex/GeoDataFileManagerImpl.java b/apex/com.android.geotz/src/main/java/com/android/geotz/apex/GeoDataFileManagerImpl.java
new file mode 100644
index 0000000..7972b62
--- /dev/null
+++ b/apex/com.android.geotz/src/main/java/com/android/geotz/apex/GeoDataFileManagerImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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.geotz.apex;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.timezone.location.provider.GeoDataFileManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * An implementation of {@link GeoDataFileManager} that reads the tzs2.dat file from a file path.
+ */
+public final class GeoDataFileManagerImpl implements GeoDataFileManager {
+
+    /**
+     * The config properties key to get the file system path of the tzs2.dat file to use for time
+     * zone boundaries.
+     */
+    private static final String RESOURCE_CONFIG_KEY_GEODATA_PATH = "geodata.path";
+
+    private File mGeoDataFile;
+
+    @Override
+    public void init(@NonNull Context context, @NonNull Properties configProperties)
+            throws IOException {
+        String geoDataPath = configProperties.getProperty(RESOURCE_CONFIG_KEY_GEODATA_PATH);
+        mGeoDataFile = new File(geoDataPath);
+        if (!(mGeoDataFile.isFile() && mGeoDataFile.canRead())) {
+            throw new IOException("File not found or is not readable: " + mGeoDataFile);
+        }
+    }
+
+    @Override
+    @NonNull
+    public File getGeoDataFile() {
+        return Objects.requireNonNull(mGeoDataFile);
+    }
+}
diff --git a/apex/com.android.geotz/src/main/java/com/android/geotz/MetricsReporterImpl.java b/apex/com.android.geotz/src/main/java/com/android/geotz/apex/MetricsReporterImpl.java
similarity index 97%
rename from apex/com.android.geotz/src/main/java/com/android/geotz/MetricsReporterImpl.java
rename to apex/com.android.geotz/src/main/java/com/android/geotz/apex/MetricsReporterImpl.java
index 597b054..b4d03d2 100644
--- a/apex/com.android.geotz/src/main/java/com/android/geotz/MetricsReporterImpl.java
+++ b/apex/com.android.geotz/src/main/java/com/android/geotz/apex/MetricsReporterImpl.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.geotz;
+package com.android.geotz.apex;
 
 import com.android.timezone.location.provider.core.MetricsReporter;
 import com.android.timezone.location.provider.core.OfflineLocationTimeZoneDelegate.ListenModeEnum;
diff --git a/app/Android.bp b/app/Android.bp
new file mode 100644
index 0000000..e217e91
--- /dev/null
+++ b/app/Android.bp
@@ -0,0 +1,38 @@
+// An example application that uses the reference
+// offlinelocationtimezoneprovider impl.
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "OfflineLocationTimeZoneProviderService",
+    manifest: "AndroidManifest.xml",
+    certificate: "platform",
+    privileged: true,
+    sdk_version: "system_31",
+    java_resource_dirs: ["resources/"],
+    java_resources: [":tzs2.dat-resources"],
+    srcs: [
+        "src/main/java/**/*.java",
+    ],
+    libs: [
+        "androidx.annotation_annotation",
+    ],
+    static_libs: [
+        "guava",
+        "offlinelocationtimezoneprovider",
+    ],
+    required: [
+        "privapp-permissions-com.android.timezone.location.provider",
+    ],
+    optimize: {
+        proguard_flags_files: ["proguard.txt"],
+    },
+}
+
+prebuilt_etc {
+    name: "privapp-permissions-com.android.timezone.location.provider",
+    src: "privapp-permissions-com.android.timezone.location.provider.xml",
+    sub_dir: "permissions",
+    filename_from_src: true,
+}
diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml
new file mode 100644
index 0000000..f17d7f6
--- /dev/null
+++ b/app/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.timezone.location.provider">
+
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application>
+        <service android:name=".OfflineLocationTimeZoneProviderService"
+            android:exported="true"
+            android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.timezone.PrimaryLocationTimeZoneProviderService" />
+            </intent-filter>
+
+            <meta-data android:name="serviceIsMultiuser" android:value="false" />
+        </service>
+    </application>
+</manifest>
diff --git a/app/privapp-permissions-com.android.timezone.location.provider.xml b/app/privapp-permissions-com.android.timezone.location.provider.xml
new file mode 100644
index 0000000..74d2aa6
--- /dev/null
+++ b/app/privapp-permissions-com.android.timezone.location.provider.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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
+  -->
+
+<!-- The permissions needed by the com.android.timezone.location.provider app. -->
+<permissions>
+    <privapp-permissions package="com.android.timezone.location.provider">
+        <permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+        <permission name="android.permission.ACCESS_COARSE_LOCATION" />
+        <permission name="android.permission.ACCESS_FINE_LOCATION" />
+        <permission name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE" />
+        <permission name="android.permission.READ_DEVICE_CONFIG" />
+        <permission name="android.permission.WAKE_LOCK" />
+    </privapp-permissions>
+</permissions>
diff --git a/app/proguard.txt b/app/proguard.txt
new file mode 100644
index 0000000..6b2b7c3
--- /dev/null
+++ b/app/proguard.txt
@@ -0,0 +1,2 @@
+# Loaded via reflection
+-keep class com.android.geotz.** {*;}
diff --git a/app/resources/offlineltzprovider.properties b/app/resources/offlineltzprovider.properties
new file mode 100644
index 0000000..9150677
--- /dev/null
+++ b/app/resources/offlineltzprovider.properties
@@ -0,0 +1,24 @@
+# Configuration for the
+# com.android.timezone.location.provider.OfflineLocationTimeZoneProviderService
+# deployed in the com.android.geotz mainline module.
+
+# The implementation of com.android.timezone.location.provider.GeoDataFileManager to use.
+geodata.file_manager_impl=com.android.geotz.app.GeoDataFileManagerImpl
+
+# The location of the tzs2.dat file to use for time zone boundaries, i.e. the
+# resource path inside the APK.
+geodata.resource=tzs2.dat
+# The expected SHA256 of the tzs2.dat file.
+geodata.sha256=f668e04cae7716184db2850e2eaf385ac2705f953eeee7ea78b745038bcdf513
+
+# The namespace to pass to android.provider.DeviceConfig for server-pushed configuration.
+# Because com.android.geotz is provided by the Google Android platform team we can reuse the
+# platform experiment namespace.
+deviceconfig.namespace=system_time
+
+# The prefix that should be applied to keys passed to android.provider.DeviceConfig.
+deviceconfig.key_prefix=geotz_app_
+
+# The implementation of com.android.timezone.location.provider.core.MetricsReporter to use.
+# This implementation uses Google's standard metrics reporting.
+metrics_reporter.impl=com.android.geotz.app.MetricsReporterImpl
diff --git a/app/src/main/java/com/android/geotz/app/GeoDataFileManagerImpl.java b/app/src/main/java/com/android/geotz/app/GeoDataFileManagerImpl.java
new file mode 100644
index 0000000..9d6f26a
--- /dev/null
+++ b/app/src/main/java/com/android/geotz/app/GeoDataFileManagerImpl.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2022 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.geotz.app;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.timezone.location.provider.GeoDataFileManager;
+import com.google.common.hash.Hashing;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * An implementation of {@link GeoDataFileManager} that copies the tzs2.dat classpath resource to
+ * an app file path for reading.
+ */
+public final class GeoDataFileManagerImpl implements GeoDataFileManager {
+
+    /**
+     * The config properties key to get the resource path of the tzs2.dat file to use for time zone
+     * boundaries.
+     */
+    private static final String RESOURCE_CONFIG_KEY_GEODATA_RESOURCE = "geodata.resource";
+
+    /**
+     * The config properties key to get the location of the tzs2.dat file to use for time zone
+     * boundaries.
+     */
+    private static final String RESOURCE_CONFIG_KEY_GEODATA_SHA256= "geodata.sha256";
+
+    private File mGeoDataFile;
+
+    @Override
+    public void init(@NonNull Context context, @NonNull Properties configProperties)
+            throws IOException {
+        File geoDataFile = new File(context.getFilesDir(), "tzs2.dat");
+        ClassLoader classLoader = getClass().getClassLoader();
+
+        String geoDataResource = configProperties.getProperty(RESOURCE_CONFIG_KEY_GEODATA_RESOURCE);
+        String expectedSha256 = configProperties.getProperty(RESOURCE_CONFIG_KEY_GEODATA_SHA256);
+        if (!geoDataFile.exists() || !Objects.equals(computeSha256(geoDataFile), expectedSha256)) {
+            // Copy the resource to the app persistent files dir.
+            copyResource(classLoader, geoDataResource, geoDataFile, expectedSha256);
+        }
+
+        mGeoDataFile = geoDataFile;
+    }
+
+    @Override
+    @NonNull
+    public File getGeoDataFile() {
+        return Objects.requireNonNull(mGeoDataFile);
+    }
+
+    private static void copyResource(@NonNull ClassLoader classLoader, @NonNull String resourceName,
+            @NonNull File targetPath, @NonNull String expectedSha256) {
+        boolean success = false;
+        try (InputStream resourceStream = classLoader.getResourceAsStream(resourceName)) {
+            if (resourceStream == null) {
+                throw new IllegalStateException("Unable to find "
+                        + " resource=" + resourceName);
+            }
+            Files.copy(resourceStream, targetPath.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            String actualSha256 = computeSha256(targetPath);
+            if (!actualSha256.equals(expectedSha256)) {
+                throw new IllegalStateException(
+                        "SHA256 expected=" + expectedSha256 + ", actual=" + actualSha256);
+            }
+            success = true;
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to copy resource from"
+                    + " resource=" + resourceName
+                    + " to targetPath=" + targetPath, e);
+        } finally {
+            if (!success) {
+                targetPath.delete();
+            }
+        }
+    }
+
+    private static String computeSha256(File file) {
+        try {
+            return com.google.common.io.Files.asByteSource(file).hash(Hashing.sha256()).toString();
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to compute hash for file=" + file);
+        }
+    }
+}
diff --git a/apex/com.android.geotz/src/main/java/com/android/geotz/MetricsReporterImpl.java b/app/src/main/java/com/android/geotz/app/MetricsReporterImpl.java
similarity index 85%
copy from apex/com.android.geotz/src/main/java/com/android/geotz/MetricsReporterImpl.java
copy to app/src/main/java/com/android/geotz/app/MetricsReporterImpl.java
index 597b054..188f290 100644
--- a/apex/com.android.geotz/src/main/java/com/android/geotz/MetricsReporterImpl.java
+++ b/app/src/main/java/com/android/geotz/app/MetricsReporterImpl.java
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.geotz;
+package com.android.geotz.app;
 
 import com.android.timezone.location.provider.core.MetricsReporter;
 import com.android.timezone.location.provider.core.OfflineLocationTimeZoneDelegate.ListenModeEnum;
 
 /**
- * The implementation of {@link MetricsReporter} used for the com.android.geotz module deployment
+ * The implementation of {@link MetricsReporter} used for the app deployment
  * of {@link com.android.timezone.location.provider.OfflineLocationTimeZoneProviderService}.
  */
 public class MetricsReporterImpl extends MetricsReporter {
@@ -28,6 +28,6 @@
     public void reportLocationListeningCompletedEvent(@ListenModeEnum int listenMode,
             long requestedDurationMillis, long actualTimeListeningMillis,
             int listeningStoppedReason) {
-        // TODO(b/172934905): Implement once the atom has landed.
+        // No-op
     }
 }
diff --git a/common/Android.bp b/common/Android.bp
index c64e06d..11077ee 100644
--- a/common/Android.bp
+++ b/common/Android.bp
@@ -32,6 +32,7 @@
     sdk_version: "31",
     min_sdk_version: "31",
     apex_available: [
+        "//apex_available:platform",
         "com.android.geotz",
     ],
 }
diff --git a/geotz_lookup/Android.bp b/geotz_lookup/Android.bp
index 9ef4f7d..21986ad 100644
--- a/geotz_lookup/Android.bp
+++ b/geotz_lookup/Android.bp
@@ -31,6 +31,7 @@
     host_supported: true,
     jarjar_rules: "jarjar-rules.txt",
     apex_available: [
+        "//apex_available:platform",
         "com.android.geotz",
     ],
 }
diff --git a/locationtzprovider/Android.bp b/locationtzprovider/Android.bp
index a6c560b..ed1eb0c 100644
--- a/locationtzprovider/Android.bp
+++ b/locationtzprovider/Android.bp
@@ -30,6 +30,7 @@
         "geotz_lookup",
     ],
     apex_available: [
+        "//apex_available:platform",
         "com.android.geotz",
     ],
 }
diff --git a/locationtzprovider/src/main/java/com/android/timezone/location/provider/EnvironmentImpl.java b/locationtzprovider/src/main/java/com/android/timezone/location/provider/EnvironmentImpl.java
index e1b1fd4..bd2056f 100644
--- a/locationtzprovider/src/main/java/com/android/timezone/location/provider/EnvironmentImpl.java
+++ b/locationtzprovider/src/main/java/com/android/timezone/location/provider/EnvironmentImpl.java
@@ -64,10 +64,11 @@
     private static final String RESOURCE_CONFIG_PROPERTIES_NAME = "offlineltzprovider.properties";
 
     /**
-     * The config properties key to get the location of the tzs2.dat file to use for time zone
-     * boundaries.
+     *
+     * The config properties key to determine how the tzs2.dat file is loaded.
      */
-    private static final String RESOURCE_CONFIG_KEY_GEODATA_PATH = "geodata.path";
+    private static final String RESOURCE_CONFIG_KEY_GEODATA_FILE_MANAGER_IMPL =
+            "geodata.file_manager_impl";
 
     /**
      * The config properties key for the namespace to pass to {@link android.provider.DeviceConfig}
@@ -88,12 +89,6 @@
      */
     private static final String RESOURCE_CONFIG_METRICS_REPORTER_IMPL = "metrics_reporter.impl";
 
-    /**
-     * An identifier that can be used to distinguish between different deployments of the same code.
-     */
-    private static final String RESOURCE_CONFIG_METRICS_REPORTER_DEPLOYMENT_IDENTIFIER =
-            "metrics_reporter.identifier";
-
     /** An arbitrary value larger than the largest time we might want to hold a wake lock. */
     private static final long WAKELOCK_ACQUIRE_MILLIS = Duration.ofMinutes(1).toMillis();
 
@@ -159,16 +154,18 @@
         mHandler = new Handler(Looper.getMainLooper());
         mExecutor = new HandlerExecutor(mHandler);
 
-        Properties configProperties = loadConfigProperties(getClass().getClassLoader());
-        mGeoDataFile = new File(configProperties.getProperty(RESOURCE_CONFIG_KEY_GEODATA_PATH));
+        ClassLoader classLoader = getClass().getClassLoader();
+        Properties configProperties = loadConfigProperties(classLoader);
+        GeoDataFileManager geoDataFileManager =
+                createGeoDataFileManager(context, classLoader, configProperties);
+        mGeoDataFile = geoDataFileManager.getGeoDataFile();
+
         mDeviceConfigNamespace = Objects.requireNonNull(
                 configProperties.getProperty(RESOURCE_CONFIG_KEY_DEVICE_CONFIG_NAMESPACE));
         mDeviceConfigKeyPrefix = Objects.requireNonNull(
                 configProperties.getProperty(RESOURCE_CONFIG_KEY_DEVICE_CONFIG_KEY_PREFIX));
 
-        String metricsReporterClassName =
-                configProperties.getProperty(RESOURCE_CONFIG_METRICS_REPORTER_IMPL);
-        mMetricsReporter = createMetricsReporter(metricsReporterClassName);
+        mMetricsReporter = createMetricsReporter(classLoader, configProperties);
 
         LocationListeningAccountant realLocationListeningAccountant =
                 createRealLocationListeningAccountant();
@@ -185,10 +182,30 @@
                 mDeviceConfigNamespace, mExecutor, this::handleDeviceConfigChanged);
     }
 
-    private MetricsReporter createMetricsReporter(@NonNull String className) {
+    private static GeoDataFileManager createGeoDataFileManager(
+            @NonNull Context context, @NonNull ClassLoader classLoader,
+            @NonNull Properties configProperties) {
+        String className =
+                configProperties.getProperty(RESOURCE_CONFIG_KEY_GEODATA_FILE_MANAGER_IMPL);
         try {
-            Class<?> clazz = Class.forName(className);
-            return (MetricsReporter) clazz.newInstance();
+            Class<?> clazz = classLoader.loadClass(className);
+            GeoDataFileManager geoDataFileManager =
+                    (GeoDataFileManager) clazz.getConstructor().newInstance();
+            geoDataFileManager.init(context, configProperties);
+            return geoDataFileManager;
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalStateException("Unable to instantiate GeoDataFileManager", e);
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to initialize GeoDataFileManager", e);
+        }
+    }
+
+    private static MetricsReporter createMetricsReporter(
+            @NonNull ClassLoader classLoader, @NonNull Properties configProperties) {
+        String className = configProperties.getProperty(RESOURCE_CONFIG_METRICS_REPORTER_IMPL);
+        try {
+            Class<?> clazz = classLoader.loadClass(className);
+            return (MetricsReporter) clazz.getConstructor().newInstance();
         } catch (ReflectiveOperationException e) {
             throw new IllegalStateException("Unable to instantiate MetricsReporter", e);
         }
diff --git a/locationtzprovider/src/main/java/com/android/timezone/location/provider/GeoDataFileManager.java b/locationtzprovider/src/main/java/com/android/timezone/location/provider/GeoDataFileManager.java
new file mode 100644
index 0000000..5c0f664
--- /dev/null
+++ b/locationtzprovider/src/main/java/com/android/timezone/location/provider/GeoDataFileManager.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.timezone.location.provider;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+/** An interface for classes that know how to obtain time zone geo data. */
+public interface GeoDataFileManager {
+
+    /**
+     * Performs any actions needed to make the geo data file available via {@link
+     * #getGeoDataFile()}.
+     */
+    void init(@NonNull Context context, @NonNull Properties configProperties) throws IOException;
+
+    /**
+     * Returns the location of the geo data file. Throws an exception if {@link
+     * #init(Context, Properties)} failed.
+     */
+    @NonNull
+    File getGeoDataFile();
+}
diff --git a/output_data/Android.bp b/output_data/Android.bp
index cc92b7c..af8a42b 100644
--- a/output_data/Android.bp
+++ b/output_data/Android.bp
@@ -27,7 +27,6 @@
 prebuilt_etc {
     name: "apex_tzs2.dat",
     src: "odbl/tzs2.dat",
-    notice: "odbl/LICENSE",
     filename: "tzs2.dat",
     installable: false,
 }
diff --git a/s2storage/Android.bp b/s2storage/Android.bp
index bf5c2c8..3f04ce4 100644
--- a/s2storage/Android.bp
+++ b/s2storage/Android.bp
@@ -26,6 +26,7 @@
         "src/readonly/java/**/*.java",
     ],
     apex_available: [
+        "//apex_available:platform",
         "com.android.geotz",
     ],
 }