AutomaticStorageManagementJobService.java revision 01a81f3502750035b8eabb6a053a61bfae4d768e
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.storagemanager.automatic;
18
19import android.app.job.JobParameters;
20import android.app.job.JobService;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.os.storage.StorageManager;
25import android.provider.Settings;
26import android.util.Log;
27
28import com.android.internal.annotations.VisibleForTesting;
29import com.android.settingslib.Utils;
30import com.android.settingslib.deviceinfo.PrivateStorageInfo;
31import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
32import com.android.settingslib.deviceinfo.StorageVolumeProvider;
33import com.android.storagemanager.overlay.FeatureFactory;
34import com.android.storagemanager.overlay.StorageManagementJobProvider;
35
36/**
37 * {@link JobService} class to start automatic storage clearing jobs to free up space. The job only
38 * starts if the device is under a certain percent of free storage.
39 */
40public class AutomaticStorageManagementJobService extends JobService {
41    private static final String TAG = "AsmJobService";
42
43    private static final long DEFAULT_LOW_FREE_PERCENT = 15;
44
45    private StorageManagementJobProvider mProvider;
46    private StorageVolumeProvider mVolumeProvider;
47    private Clock mClock;
48
49    @Override
50    public boolean onStartJob(JobParameters args) {
51        // We need to double-check the preconditions here because they are not enforced for a
52        // periodic job.
53        if (!preconditionsFulfilled()) {
54            // By telling the system to re-schedule the job, it will attempt to execute again at a
55            // later idle window -- possibly one where we are charging.
56            jobFinished(args, true);
57            return false;
58        }
59
60        mProvider = FeatureFactory.getFactory(this).getStorageManagementJobProvider();
61        if (maybeDisableDueToPolicy(mProvider, getContentResolver(), getClock())) {
62            jobFinished(args, false);
63            return false;
64        }
65
66        if (!volumeNeedsManagement()) {
67            Log.i(TAG, "Skipping automatic storage management.");
68            Settings.Secure.putLong(getContentResolver(),
69                    Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
70                    System.currentTimeMillis());
71            jobFinished(args, false);
72            return false;
73        }
74
75        boolean isEnabled =
76                Settings.Secure.getInt(getContentResolver(),
77                        Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 0) != 0;
78        if (!isEnabled) {
79            Intent maybeShowNotificationIntent =
80                    new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION);
81            maybeShowNotificationIntent.setClass(getApplicationContext(),
82                    NotificationController.class);
83            getApplicationContext().sendBroadcast(maybeShowNotificationIntent);
84            jobFinished(args, false);
85            return false;
86        }
87
88        if (mProvider != null) {
89            return mProvider.onStartJob(this, args, getDaysToRetain());
90        }
91
92        jobFinished(args, false);
93        return false;
94    }
95
96    @Override
97    public boolean onStopJob(JobParameters args) {
98        if (mProvider != null) {
99            return mProvider.onStopJob(this, args);
100        }
101
102        return false;
103    }
104
105    void setStorageVolumeProvider(StorageVolumeProvider storageProvider) {
106        mVolumeProvider = storageProvider;
107    }
108
109    private int getDaysToRetain() {
110        return Settings.Secure.getInt(
111                getContentResolver(),
112                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
113                Utils.getDefaultStorageManagerDaysToRetain(getResources()));
114    }
115
116    private boolean volumeNeedsManagement() {
117        if (mVolumeProvider == null) {
118            mVolumeProvider = new StorageManagerVolumeProvider(
119                    getSystemService(StorageManager.class));
120        }
121
122        PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(mVolumeProvider);
123
124        long lowStorageThreshold = (info.totalBytes * DEFAULT_LOW_FREE_PERCENT) / 100;
125        return info.freeBytes < lowStorageThreshold;
126    }
127
128    private boolean preconditionsFulfilled() {
129        // NOTE: We don't check the idle state here because this job should be running in idle
130        // maintenance windows. During the idle maintenance window, the device is -technically- not
131        // idle. For more information, see PowerManager.isDeviceIdleMode().
132        Context context = getApplicationContext();
133        return JobPreconditions.isCharging(context);
134    }
135
136    /** Returns if ASM was disabled due to policy. * */
137    @VisibleForTesting
138    static boolean maybeDisableDueToPolicy(
139            StorageManagementJobProvider provider, ContentResolver cr, Clock clock) {
140        if (provider == null || cr == null) {
141            return false;
142        }
143
144        final long disabledThresholdMillis = provider.getDisableThresholdMillis(cr);
145        final long currentTime = clock.currentTimeMillis();
146        final boolean disabledByPolicyInThePast =
147                Settings.Secure.getInt(
148                                cr,
149                                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_TURNED_OFF_BY_POLICY,
150                                0)
151                        != 0;
152        if (currentTime > disabledThresholdMillis && !disabledByPolicyInThePast) {
153            Settings.Secure.putInt(
154                    cr, Settings.Secure.AUTOMATIC_STORAGE_MANAGER_TURNED_OFF_BY_POLICY, 1);
155            Settings.Secure.putInt(cr, Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 0);
156            return true;
157        }
158
159        return false;
160    }
161
162    private Clock getClock() {
163        if (mClock == null) {
164            mClock = new Clock();
165        }
166        return mClock;
167    }
168
169    @VisibleForTesting
170    void setClock(Clock clock) {
171        mClock = clock;
172    }
173
174    /** Clock provides the current time. */
175    protected static class Clock {
176        /** Returns the current time in milliseconds. */
177        public long currentTimeMillis() {
178            return System.currentTimeMillis();
179        }
180    }
181}
182