diff options
6 files changed, 112 insertions, 0 deletions
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 58e4051b5111..248e66e21384 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3606,6 +3606,10 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> + <service android:name="com.android.server.PreloadsFileCacheExpirationJobService" + android:permission="android.permission.BIND_JOB_SERVICE" > + </service> + </application> </manifest> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 67a3aeec6547..68e766e46279 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2691,6 +2691,10 @@ <!-- List of packages to enable in carrier demo mode (comma separated). --> <string name="config_carrierDemoModePackages" translatable="false"></string> + <!-- Number of days preloaded file cache should be preserved on a device before it can be + deleted --> + <integer name="config_keepPreloadsMinDays">7</integer> + <!-- Flag indicating whether round icons should be parsed from the application manifest. --> <bool name="config_useRoundIcon">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f9fe333cae7f..4ef3922aa1fe 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -421,6 +421,7 @@ <java-symbol type="integer" name="config_valid_wappush_index" /> <java-symbol type="integer" name="config_overrideHasPermanentMenuKey" /> <java-symbol type="integer" name="config_mdc_initial_max_retry" /> + <java-symbol type="integer" name="config_keepPreloadsMinDays" /> <java-symbol type="bool" name="config_hasPermanentDpad" /> <java-symbol type="color" name="tab_indicator_text_v4" /> diff --git a/services/core/java/com/android/server/PreloadsFileCacheExpirationJobService.java b/services/core/java/com/android/server/PreloadsFileCacheExpirationJobService.java new file mode 100644 index 000000000000..6fd0256fcbfd --- /dev/null +++ b/services/core/java/com/android/server/PreloadsFileCacheExpirationJobService.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 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; + +import android.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.content.ComponentName; +import android.content.Context; +import android.content.res.Resources; +import android.os.Environment; +import android.os.SystemProperties; +import android.util.Slog; +import android.util.TimeUtils; + +import com.android.internal.R; + +import java.util.concurrent.TimeUnit; + +/** + * {@link JobService} that marks + * {@link Environment#getDataPreloadsFileCacheDirectory() preloaded file cache} as expired after a + * pre-configured timeout. + */ +public class PreloadsFileCacheExpirationJobService extends JobService { + private static final boolean DEBUG = false; // Do not submit with true + private static final String TAG = "PreloadsFileCacheExpirationJobService"; + + // TODO move all JOB_IDs into a single class to avoid collisions + private static final int JOB_ID = 100500; + + private static final String PERSIST_SYS_PRELOADS_FILE_CACHE_EXPIRED + = "persist.sys.preloads.file_cache_expired"; + + public static void schedule(Context context) { + int keepPreloadsMinDays = Resources.getSystem().getInteger( + R.integer.config_keepPreloadsMinDays); // Default is 1 week + long keepPreloadsMinTimeoutMs = DEBUG ? TimeUnit.MINUTES.toMillis(2) + : TimeUnit.DAYS.toMillis(keepPreloadsMinDays); + long keepPreloadsMaxTimeoutMs = DEBUG ? TimeUnit.MINUTES.toMillis(3) + : TimeUnit.DAYS.toMillis(keepPreloadsMinDays + 1); + + if (DEBUG) { + StringBuilder sb = new StringBuilder("Scheduling expiration job to run in "); + TimeUtils.formatDuration(keepPreloadsMinTimeoutMs, sb); + Slog.i(TAG, sb.toString()); + } + JobInfo expirationJob = new JobInfo.Builder(JOB_ID, + new ComponentName(context, PreloadsFileCacheExpirationJobService.class)) + .setPersisted(true) + .setMinimumLatency(keepPreloadsMinTimeoutMs) + .setOverrideDeadline(keepPreloadsMaxTimeoutMs) + .build(); + + JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); + jobScheduler.schedule(expirationJob); + } + + @Override + public boolean onStartJob(JobParameters params) { + SystemProperties.set(PERSIST_SYS_PRELOADS_FILE_CACHE_EXPIRED, "1"); + Slog.i(TAG, "Set " + PERSIST_SYS_PRELOADS_FILE_CACHE_EXPIRED + "=1"); + return false; + } + + @Override + public boolean onStopJob(JobParameters params) { + return false; + } +} diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java index 472f98455d6a..43c38a6422a4 100644 --- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java +++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java @@ -69,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; +import com.android.server.PreloadsFileCacheExpirationJobService; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.am.ActivityManagerService; @@ -259,6 +260,7 @@ public class RetailDemoModeService extends SystemService { if (!deletePreloadsFolderContents()) { Slog.w(TAG, "Failed to delete preloads folder contents"); } + PreloadsFileCacheExpirationJobService.schedule(mInjector.getContext()); }); stopDemoMode(); @@ -443,6 +445,11 @@ public class RetailDemoModeService extends SystemService { mInjector.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0; } + /** + * Deletes contents of {@link Environment#getDataPreloadsDirectory()}, + * but leave {@link Environment#getDataPreloadsFileCacheDirectory()} + * @return true if contents was sucessfully deleted + */ private boolean deletePreloadsFolderContents() { final File dir = mInjector.getDataPreloadsDirectory(); final File[] files = FileUtils.listFilesOrEmpty(dir); diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java index d18457b79c55..ce5b8cbb9bed 100644 --- a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java @@ -33,6 +33,8 @@ import android.app.ActivityManagerInternal; import android.app.Notification; import android.app.NotificationManager; import android.app.RetailDemoModeServiceInternal; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -97,6 +99,7 @@ public class RetailDemoModeServiceTest { private @Mock AudioManager mAudioManager; private @Mock WifiManager mWifiManager; private @Mock LockPatternUtils mLockPatternUtils; + private @Mock JobScheduler mJobScheduler; private MockPreloadAppsInstaller mPreloadAppsInstaller; private MockContentResolver mContentResolver; private MockContactsProvider mContactsProvider; @@ -110,6 +113,12 @@ public class RetailDemoModeServiceTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + Context originalContext = InstrumentationRegistry.getContext(); + when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo()); + when(mContext.getResources()).thenReturn(originalContext.getResources()); + when(mContext.getSystemServiceName(eq(JobScheduler.class))).thenReturn( + Context.JOB_SCHEDULER_SERVICE); + when(mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE)).thenReturn(mJobScheduler); mContentResolver = new MockContentResolver(mContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mContactsProvider = new MockContactsProvider(mContext); @@ -218,6 +227,8 @@ public class RetailDemoModeServiceTest { // verify that the preloaded directory is emptied. assertEquals("Preloads directory is not emptied", 0, mTestPreloadsDir.list().length); + // Verify that the expiration job was scheduled + verify(mJobScheduler).schedule(any(JobInfo.class)); } @Test |