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