1532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn/* 2532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * Copyright (C) 2017 The Android Open Source Project 3532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * 4532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 5532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * you may not use this file except in compliance with the License. 6532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * You may obtain a copy of the License at 7532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * 8532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 9532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * 10532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 11532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 12532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * See the License for the specific language governing permissions and 14532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * limitations under the License 15532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn */ 16532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 17532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornpackage com.android.server.job.controllers; 18532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 19532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.content.BroadcastReceiver; 20532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.content.Context; 21532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.content.Intent; 22532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.content.IntentFilter; 23532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.os.SystemClock; 24532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.os.UserHandle; 25f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackbornimport android.util.ArraySet; 26532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.util.Slog; 27532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 28532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport com.android.internal.annotations.VisibleForTesting; 29532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport com.android.server.job.JobSchedulerService; 30532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport com.android.server.job.StateChangedListener; 31532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport com.android.server.storage.DeviceStorageMonitorService; 32532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 33532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport java.io.PrintWriter; 34532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 35532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn/** 36532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * Simple controller that tracks the status of the device's storage. 37532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn */ 386466c1cc5efc4ff05fabdd670cf78a6a7ca45afbDianne Hackbornpublic final class StorageController extends StateController { 39532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private static final String TAG = "JobScheduler.Stor"; 40532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 41532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private static final Object sCreationLock = new Object(); 42532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private static volatile StorageController sController; 43532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 44f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackborn private final ArraySet<JobStatus> mTrackedTasks = new ArraySet<JobStatus>(); 45532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private StorageTracker mStorageTracker; 46532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 47532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public static StorageController get(JobSchedulerService taskManagerService) { 48532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn synchronized (sCreationLock) { 49532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (sController == null) { 50532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn sController = new StorageController(taskManagerService, 51532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn taskManagerService.getContext(), taskManagerService.getLock()); 52532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 53532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 54532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return sController; 55532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 56532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 57532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @VisibleForTesting 58532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public StorageTracker getTracker() { 59532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return mStorageTracker; 60532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 61532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 62532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @VisibleForTesting 63532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public static StorageController getForTesting(StateChangedListener stateChangedListener, 64532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn Context context) { 65532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return new StorageController(stateChangedListener, context, new Object()); 66532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 67532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 68532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private StorageController(StateChangedListener stateChangedListener, Context context, 69532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn Object lock) { 70532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn super(stateChangedListener, context, lock); 71532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mStorageTracker = new StorageTracker(); 72532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mStorageTracker.startTracking(); 73532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 74532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 75532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @Override 76532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) { 77532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (taskStatus.hasStorageNotLowConstraint()) { 78532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mTrackedTasks.add(taskStatus); 79f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackborn taskStatus.setTrackingController(JobStatus.TRACKING_STORAGE); 80532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn taskStatus.setStorageNotLowConstraintSatisfied(mStorageTracker.isStorageNotLow()); 81532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 82532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 83532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 84532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @Override 85f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackborn public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob, 86f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackborn boolean forUpdate) { 87f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackborn if (taskStatus.clearTrackingController(JobStatus.TRACKING_STORAGE)) { 88532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mTrackedTasks.remove(taskStatus); 89532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 90532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 91532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 92532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private void maybeReportNewStorageState() { 93532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn final boolean storageNotLow = mStorageTracker.isStorageNotLow(); 94532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn boolean reportChange = false; 95532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn synchronized (mLock) { 96532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn for (int i = mTrackedTasks.size() - 1; i >= 0; i--) { 97f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackborn final JobStatus ts = mTrackedTasks.valueAt(i); 98532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn boolean previous = ts.setStorageNotLowConstraintSatisfied(storageNotLow); 99532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (previous != storageNotLow) { 100532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn reportChange = true; 101532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 102532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 103532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 104532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn // Let the scheduler know that state has changed. This may or may not result in an 105532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn // execution. 106532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (reportChange) { 107532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mStateChangedListener.onControllerStateChanged(); 108532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 109532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn // Also tell the scheduler that any ready jobs should be flushed. 110532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (storageNotLow) { 111532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mStateChangedListener.onRunJobNow(null); 112532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 113532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 114532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 1156466c1cc5efc4ff05fabdd670cf78a6a7ca45afbDianne Hackborn public final class StorageTracker extends BroadcastReceiver { 116532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn /** 117532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * Track whether storage is low. 118532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn */ 119532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private boolean mStorageLow; 120532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn /** Sequence number of last broadcast. */ 121532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private int mLastBatterySeq = -1; 122532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 123532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public StorageTracker() { 124532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 125532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 126532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public void startTracking() { 127532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn IntentFilter filter = new IntentFilter(); 128532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 129532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn // Storage status. Just need to register, since STORAGE_LOW is a sticky 130532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn // broadcast we will receive that if it is currently active. 131532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW); 132532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); 133532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mContext.registerReceiver(this, filter); 134532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 135532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 136532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public boolean isStorageNotLow() { 137532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return !mStorageLow; 138532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 139532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 140532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public int getSeq() { 141532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return mLastBatterySeq; 142532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 143532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 144532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @Override 145532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public void onReceive(Context context, Intent intent) { 146532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn onReceiveInternal(intent); 147532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 148532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 149532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @VisibleForTesting 150532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public void onReceiveInternal(Intent intent) { 151532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn final String action = intent.getAction(); 152532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mLastBatterySeq = intent.getIntExtra(DeviceStorageMonitorService.EXTRA_SEQUENCE, 153532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mLastBatterySeq); 154532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) { 155532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (DEBUG) { 156532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn Slog.d(TAG, "Available storage too low to do work. @ " 157532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn + SystemClock.elapsedRealtime()); 158532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 159532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mStorageLow = true; 160532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) { 161532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (DEBUG) { 162532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn Slog.d(TAG, "Available stoage high enough to do work. @ " 163532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn + SystemClock.elapsedRealtime()); 164532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 165532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn mStorageLow = false; 166532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn maybeReportNewStorageState(); 167532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 168532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 169532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 170532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 171532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @Override 172532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { 173532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.print("Storage: not low = "); 174532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.print(mStorageTracker.isStorageNotLow()); 175532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.print(", seq="); 176532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(mStorageTracker.getSeq()); 177532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.print("Tracking "); 178532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.print(mTrackedTasks.size()); 179532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(":"); 180532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn for (int i = 0; i < mTrackedTasks.size(); i++) { 181f9bac16d61db0fceb15484587ecf876c2b802c37Dianne Hackborn final JobStatus js = mTrackedTasks.valueAt(i); 182532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (!js.shouldDump(filterUid)) { 183532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn continue; 184532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 185532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.print(" #"); 186532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn js.printUniqueId(pw); 187532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.print(" from "); 188532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn UserHandle.formatUid(pw, js.getSourceUid()); 189532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(); 190532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 191532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 192532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn} 193