diff options
| author | Daniel Nishi <dhnishi@google.com> | 2017-01-23 14:33:42 -0800 |
|---|---|---|
| committer | Daniel Nishi <dhnishi@google.com> | 2017-02-17 10:26:16 -0800 |
| commit | cf9d19e030830fd808d59f1c97edf65e66f675d6 (patch) | |
| tree | 7d27e4f71ff44e24ce8aa36038dc5e88b4eb8a70 /core/java | |
| parent | ceb250424a32ef45549fa728adcd766cb7c35b54 (diff) | |
First pass at adding the cache quota suggestions.
This currently integrates with installd, but not with
any framework API to expose this information to apps.
The first pass, as per the design doc, adds a service
which polls for large changes in the file system free space.
If enough spaces changes, it begins a recalculation of the
cache quotas and pipes the information down to installd.
This calculation is done in the updateable ExtServices.
Further enhancements in later patches include integrating this
to listen to package install and removal events, caching the
last computed quota values into an XML file on disk to load
on boot, and exposing the information to apps.
Bug: 33965858
Test: ExtServices unit test
Change-Id: Ie39f228b73532cb6ce2f98529f7c5df0839202ae
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/usage/CacheQuotaHint.aidl | 20 | ||||
| -rw-r--r-- | core/java/android/app/usage/CacheQuotaHint.java | 142 | ||||
| -rw-r--r-- | core/java/android/app/usage/CacheQuotaService.java | 112 | ||||
| -rw-r--r-- | core/java/android/app/usage/ICacheQuotaService.aidl | 25 | ||||
| -rw-r--r-- | core/java/android/app/usage/UsageStatsManagerInternal.java | 5 |
5 files changed, 303 insertions, 1 deletions
diff --git a/core/java/android/app/usage/CacheQuotaHint.aidl b/core/java/android/app/usage/CacheQuotaHint.aidl new file mode 100644 index 000000000000..0470ea730b65 --- /dev/null +++ b/core/java/android/app/usage/CacheQuotaHint.aidl @@ -0,0 +1,20 @@ +/* + * 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 android.app.usage; + +/** {@hide} */ +parcelable CacheQuotaHint;
\ No newline at end of file diff --git a/core/java/android/app/usage/CacheQuotaHint.java b/core/java/android/app/usage/CacheQuotaHint.java new file mode 100644 index 000000000000..4b6f99b43a09 --- /dev/null +++ b/core/java/android/app/usage/CacheQuotaHint.java @@ -0,0 +1,142 @@ +/* + * 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 android.app.usage; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * CacheQuotaRequest represents a triplet of a uid, the volume UUID it is stored upon, and + * its usage stats. When processed, it obtains a cache quota as defined by the system which + * allows apps to understand how much cache to use. + * {@hide} + */ +@SystemApi +public final class CacheQuotaHint implements Parcelable { + public static final long QUOTA_NOT_SET = -1; + private final String mUuid; + private final int mUid; + private final UsageStats mUsageStats; + private final long mQuota; + + /** + * Create a new request. + * @param builder A builder for this object. + */ + public CacheQuotaHint(Builder builder) { + this.mUuid = builder.mUuid; + this.mUid = builder.mUid; + this.mUsageStats = builder.mUsageStats; + this.mQuota = builder.mQuota; + } + + public String getVolumeUuid() { + return mUuid; + } + + public int getUid() { + return mUid; + } + + public long getQuota() { + return mQuota; + } + + public UsageStats getUsageStats() { + return mUsageStats; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mUuid); + dest.writeInt(mUid); + dest.writeLong(mQuota); + dest.writeParcelable(mUsageStats, 0); + } + + @Override + public int describeContents() { + return 0; + } + + public static final class Builder { + private String mUuid; + private int mUid; + private UsageStats mUsageStats; + private long mQuota; + + public Builder() { + } + + public Builder(CacheQuotaHint hint) { + setVolumeUuid(hint.getVolumeUuid()); + setUid(hint.getUid()); + setUsageStats(hint.getUsageStats()); + setQuota(hint.getQuota()); + } + + public @NonNull Builder setVolumeUuid(@Nullable String uuid) { + mUuid = uuid; + return this; + } + + public @NonNull Builder setUid(int uid) { + Preconditions.checkArgumentPositive(uid, "Proposed uid was not positive."); + mUid = uid; + return this; + } + + public @NonNull Builder setUsageStats(@Nullable UsageStats stats) { + mUsageStats = stats; + return this; + } + + public @NonNull Builder setQuota(long quota) { + Preconditions.checkArgument((quota >= QUOTA_NOT_SET)); + mQuota = quota; + return this; + } + + public @NonNull CacheQuotaHint build() { + Preconditions.checkNotNull(mUsageStats); + return new CacheQuotaHint(this); + } + } + + public static final Parcelable.Creator<CacheQuotaHint> CREATOR = + new Creator<CacheQuotaHint>() { + @Override + public CacheQuotaHint createFromParcel(Parcel in) { + final Builder builder = new Builder(); + return builder.setVolumeUuid(in.readString()) + .setUid(in.readInt()) + .setQuota(in.readLong()) + .setUsageStats(in.readParcelable(UsageStats.class.getClassLoader())) + .build(); + } + + @Override + public CacheQuotaHint[] newArray(int size) { + return new CacheQuotaHint[size]; + } + }; +} diff --git a/core/java/android/app/usage/CacheQuotaService.java b/core/java/android/app/usage/CacheQuotaService.java new file mode 100644 index 000000000000..b9430ab97e06 --- /dev/null +++ b/core/java/android/app/usage/CacheQuotaService.java @@ -0,0 +1,112 @@ +/* + * 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 android.app.usage; + +import android.annotation.SystemApi; +import android.app.Service; +import android.app.usage.ICacheQuotaService; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteCallback; +import android.util.Log; +import android.util.Pair; + +import java.util.List; + +/** + * CacheQuoteService defines a service which accepts cache quota requests and processes them, + * thereby filling out how much quota each request deserves. + * {@hide} + */ +@SystemApi +public abstract class CacheQuotaService extends Service { + private static final String TAG = "CacheQuotaService"; + + /** + * The {@link Intent} action that must be declared as handled by a service + * in its manifest for the system to recognize it as a quota providing service. + */ + public static final String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService"; + + /** {@hide} **/ + public static final String REQUEST_LIST_KEY = "requests"; + + private CacheQuotaServiceWrapper mWrapper; + private Handler mHandler; + + @Override + public void onCreate() { + super.onCreate(); + mWrapper = new CacheQuotaServiceWrapper(); + mHandler = new ServiceHandler(getMainLooper()); + } + + @Override + public IBinder onBind(Intent intent) { + return mWrapper; + } + + /** + * Processes the cache quota list upon receiving a list of requests. + * @param requests A list of cache quotas to fulfill. + * @return A completed list of cache quota requests. + */ + public abstract List<CacheQuotaHint> onComputeCacheQuotaHints( + List<CacheQuotaHint> requests); + + private final class CacheQuotaServiceWrapper extends ICacheQuotaService.Stub { + @Override + public void computeCacheQuotaHints( + RemoteCallback callback, List<CacheQuotaHint> requests) { + final Pair<RemoteCallback, List<CacheQuotaHint>> pair = + Pair.create(callback, requests); + Message msg = mHandler.obtainMessage(ServiceHandler.MSG_SEND_LIST, pair); + mHandler.sendMessage(msg); + } + } + + private final class ServiceHandler extends Handler { + public static final int MSG_SEND_LIST = 1; + + public ServiceHandler(Looper looper) { + super(looper, null, true); + } + + @Override + public void handleMessage(Message msg) { + final int action = msg.what; + switch (action) { + case MSG_SEND_LIST: + final Pair<RemoteCallback, List<CacheQuotaHint>> pair = + (Pair<RemoteCallback, List<CacheQuotaHint>>) msg.obj; + List<CacheQuotaHint> processed = onComputeCacheQuotaHints(pair.second); + final Bundle data = new Bundle(); + data.putParcelableList(REQUEST_LIST_KEY, processed); + + final RemoteCallback callback = pair.first; + callback.sendResult(data); + break; + default: + Log.w(TAG, "Handling unknown message: " + action); + } + } + } +} diff --git a/core/java/android/app/usage/ICacheQuotaService.aidl b/core/java/android/app/usage/ICacheQuotaService.aidl new file mode 100644 index 000000000000..8d984e0bf7b4 --- /dev/null +++ b/core/java/android/app/usage/ICacheQuotaService.aidl @@ -0,0 +1,25 @@ +/* + * 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 android.app.usage; + +import android.os.RemoteCallback; +import android.app.usage.CacheQuotaHint; + +/** {@hide} */ +oneway interface ICacheQuotaService { + void computeCacheQuotaHints(in RemoteCallback callback, in List<CacheQuotaHint> requests); +} diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index a6f91fe17227..08595dd1b3b4 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -19,7 +19,7 @@ package android.app.usage; import android.content.ComponentName; import android.content.res.Configuration; -import java.io.IOException; +import java.util.List; /** * UsageStatsManager local system service interface. @@ -127,4 +127,7 @@ public abstract class UsageStatsManagerInternal { public abstract void applyRestoredPayload(int user, String key, byte[] payload); + /* Cache Quota Service API */ + public abstract List<UsageStats> queryUsageStatsForUser( + int userId, int interval, long beginTime, long endTime); } |
