Merge "Sets OWNERS file for wm tests."
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 29957e4..e4dee3e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5881,6 +5881,7 @@
public static final class TvInputManager.Hardware {
method public void overrideAudioSink(int, String, int, int, int);
+ method public void overrideAudioSink(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) int, int, int);
method public void setStreamVolume(float);
method public boolean setSurface(android.view.Surface, android.media.tv.TvStreamConfig);
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c6c64b0..f94ee85 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -28,8 +28,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.app.PropertyInvalidatedCache;
+import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache;
import android.bluetooth.BluetoothDevice.Transport;
import android.bluetooth.BluetoothProfile.ConnectionPolicy;
import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
@@ -676,14 +675,15 @@
"android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
/** The profile is in disconnected state */
- public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
+ public static final int STATE_DISCONNECTED =
+ 0; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
/** The profile is in connecting state */
- public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
+ public static final int STATE_CONNECTING = 1; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
/** The profile is in connected state */
- public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
+ public static final int STATE_CONNECTED = 2; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
/** The profile is in disconnecting state */
public static final int STATE_DISCONNECTING =
- BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
+ 3; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
/** @hide */
public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
@@ -1044,6 +1044,7 @@
return false;
}
+ /*
private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state";
private final PropertyInvalidatedCache<Void, Integer> mBluetoothGetStateCache =
@@ -1059,17 +1060,22 @@
}
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableBluetoothGetStateCache() {
mBluetoothGetStateCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateBluetoothGetStateCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY);
}
+ */
/**
* Fetch the current bluetooth state. If the service is down, return
@@ -1081,14 +1087,12 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- state = mBluetoothGetStateCache.query(null);
+ //state = mBluetoothGetStateCache.query(null);
+ state = mService.getState();
}
- } catch (RuntimeException e) {
- if (e.getCause() instanceof RemoteException) {
- Log.e(TAG, "", e.getCause());
- } else {
- throw e;
- }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ e.rethrowFromSystemServer();
} finally {
mServiceLock.readLock().unlock();
}
@@ -2100,6 +2104,7 @@
}
}
+ /*
private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY =
"cache_key.bluetooth.is_offloaded_filtering_supported";
private final PropertyInvalidatedCache<Void, Boolean> mBluetoothFilteringCache =
@@ -2122,17 +2127,22 @@
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableIsOffloadedFilteringSupportedCache() {
mBluetoothFilteringCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateIsOffloadedFilteringSupportedCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY);
}
+ */
/**
* Return true if offloaded filters are supported
@@ -2145,7 +2155,18 @@
if (!getLeAccess()) {
return false;
}
- return mBluetoothFilteringCache.query(null);
+ //return mBluetoothFilteringCache.query(null);
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ return mService.isOffloadedFilteringSupported();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return false;
}
/**
@@ -2551,15 +2572,13 @@
return supportedProfiles;
}
+ /*
private static final String BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY =
"cache_key.bluetooth.get_adapter_connection_state";
private final PropertyInvalidatedCache<Void, Integer>
mBluetoothGetAdapterConnectionStateCache =
new PropertyInvalidatedCache<Void, Integer> (
8, BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY) {
- /**
- * This method must not be called when mService is null.
- */
@Override
@SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(Void query) {
@@ -2570,18 +2589,23 @@
}
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableGetAdapterConnectionStateCache() {
mBluetoothGetAdapterConnectionStateCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateGetAdapterConnectionStateCache() {
PropertyInvalidatedCache.invalidateCache(
BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY);
}
+ */
/**
* Get the current connection state of the local Bluetooth adapter.
@@ -2605,20 +2629,18 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mBluetoothGetAdapterConnectionStateCache.query(null);
+ return mService.getAdapterConnectionState();
}
- } catch (RuntimeException e) {
- if (e.getCause() instanceof RemoteException) {
- Log.e(TAG, "getConnectionState:", e.getCause());
- } else {
- throw e;
- }
+ //return mBluetoothGetAdapterConnectionStateCache.query(null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to getConnectionState, error: ", e);
} finally {
mServiceLock.readLock().unlock();
}
return BluetoothAdapter.STATE_DISCONNECTED;
}
+ /*
private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY =
"cache_key.bluetooth.get_profile_connection_state";
private final PropertyInvalidatedCache<Integer, Integer>
@@ -2646,17 +2668,22 @@
query);
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableGetProfileConnectionStateCache() {
mGetProfileConnectionStateCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateGetProfileConnectionStateCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY);
}
+ */
/**
* Get the current connection state of a profile.
@@ -2678,7 +2705,18 @@
if (getState() != STATE_ON) {
return BluetoothProfile.STATE_DISCONNECTED;
}
- return mGetProfileConnectionStateCache.query(new Integer(profile));
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ mService.getProfileConnectionState(profile);
+ }
+ //return mGetProfileConnectionStateCache.query(new Integer(profile));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to getProfileConnectionState, error: ", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return BluetoothProfile.STATE_DISCONNECTED;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 93f0268..1edf5cc 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -23,8 +23,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.app.PropertyInvalidatedCache;
+import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
import android.bluetooth.annotations.RequiresBluetoothScanPermission;
@@ -1597,6 +1596,7 @@
return false;
}
+ /*
private static final String BLUETOOTH_BONDING_CACHE_PROPERTY =
"cache_key.bluetooth.get_bond_state";
private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache =
@@ -1612,16 +1612,19 @@
}
}
};
+ */
/** @hide */
- public void disableBluetoothGetBondStateCache() {
+ /* public void disableBluetoothGetBondStateCache() {
mBluetoothBondCache.disableLocal();
- }
+ } */
/** @hide */
+ /*
public static void invalidateBluetoothGetBondStateCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY);
}
+ */
/**
* Get the bond state of the remote device.
@@ -1643,13 +1646,11 @@
return BOND_NONE;
}
try {
- return mBluetoothBondCache.query(this);
- } catch (RuntimeException e) {
- if (e.getCause() instanceof RemoteException) {
- Log.e(TAG, "", e);
- } else {
- throw e;
- }
+ //return mBluetoothBondCache.query(this);
+ return sService.getBondState(this, mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to ", e);
+ e.rethrowFromSystemServer();
}
return BOND_NONE;
}
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 5c28553..3193826 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -96,6 +96,141 @@
*/
public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
+ /**
+ * Action sent in the intent when an error occurred.
+ *
+ * @hide
+ */
+ public static final String ACTION_VPN_MANAGER_ERROR = "android.net.action.VPN_MANAGER_ERROR";
+
+ /**
+ * An IKE protocol error. Codes are the codes from IkeProtocolException, RFC 7296.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_ERROR_IKE = "android.net.category.ERROR_IKE";
+
+ /**
+ * User deactivated the VPN, either by turning it off or selecting a different VPN provider.
+ * The error code is always 0.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_ERROR_USER_DEACTIVATED =
+ "android.net.category.ERROR_USER_DEACTIVATED";
+
+ /**
+ * Network error. Error codes are ERROR_CODE_NETWORK_*.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_ERROR_NETWORK = "android.net.category.ERROR_NETWORK";
+
+ /**
+ * The key of the session that experienced this error, as returned by
+ * startProvisionedVpnProfileSession.
+ *
+ * @hide
+ */
+ public static final String EXTRA_SESSION_KEY = "android.net.extra.SESSION_KEY";
+
+ /**
+ * Extra for the Network object that was the underlying network at the time of the failure, or
+ * null if none.
+ *
+ * @hide
+ */
+ public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK";
+
+ /**
+ * The NetworkCapabilities of the underlying network.
+ *
+ * @hide
+ */
+ public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES =
+ "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES";
+
+ /**
+ * The LinkProperties of the underlying network.
+ *
+ * @hide
+ */
+ public static final String EXTRA_UNDERLYING_LINK_PROPERTIES =
+ "android.net.extra.UNDERLYING_LINK_PROPERTIES";
+
+ /**
+ * A long timestamp with SystemClock.elapsedRealtime base for when the event happened.
+ *
+ * @hide
+ */
+ public static final String EXTRA_TIMESTAMP = "android.net.extra.TIMESTAMP";
+
+ /**
+ * Extra for the error type. This is ERROR_NOT_RECOVERABLE or ERROR_RECOVERABLE.
+ *
+ * @hide
+ */
+ public static final String EXTRA_ERROR_TYPE = "android.net.extra.ERROR_TYPE";
+
+ /**
+ * Extra for the error code. The value will be 0 for CATEGORY_ERROR_USER_DEACTIVATED, one of
+ * ERROR_CODE_NETWORK_* for ERROR_CATEGORY_NETWORK or one of values defined in
+ * IkeProtocolException#ErrorType for CATEGORY_ERROR_IKE.
+ *
+ * @hide
+ */
+ public static final String EXTRA_ERROR_CODE = "android.net.extra.ERROR_CODE";
+
+ /**
+ * This error is fatal, e.g. the VPN was disabled or configuration error. The stack will not
+ * retry connection.
+ *
+ * @hide
+ */
+ public static final int ERROR_NOT_RECOVERABLE = 1;
+
+ /**
+ * The stack experienced an error but will retry with exponential backoff, e.g. network timeout.
+ *
+ * @hide
+ */
+ public static final int ERROR_RECOVERABLE = 2;
+
+ /**
+ * An error code to indicate that there was an UnknownHostException.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_UNKNOWN_HOST = 0;
+
+ /**
+ * An error code to indicate that there is a SocketTimeoutException.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_TIMEOUT = 1;
+
+ /**
+ * An error code to indicate that the connection is refused.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_CONNECT = 2;
+
+ /**
+ * An error code to indicate the connection was reset. (e.g. SocketException)
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_CONNECTION_RESET = 3;
+
+ /**
+ * An error code to indicate that there is an IOException.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_IO = 4;
+
/** @hide */
@IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY,
TYPE_VPN_OEM})
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 591cf81..c11502f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6235,6 +6235,11 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+ <service android:name="com.android.server.SmartStorageMaintIdler"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
<service android:name="com.android.server.ZramWriteback"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index efd9d10..420f4ef 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -18,6 +18,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -27,6 +28,8 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFormat.Encoding;
import android.media.PlaybackParams;
import android.net.Uri;
import android.os.Binder;
@@ -59,6 +62,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -2998,6 +3002,16 @@
return false;
}
+ /**
+ * Override default audio sink from audio policy.
+ *
+ * @param audioType device type of the audio sink to override with.
+ * @param audioAddress device address of the audio sink to override with.
+ * @param samplingRate desired sampling rate. Use default when it's 0.
+ * @param channelMask desired channel mask. Use default when it's
+ * AudioFormat.CHANNEL_OUT_DEFAULT.
+ * @param format desired format. Use default when it's AudioFormat.ENCODING_DEFAULT.
+ */
public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
int channelMask, int format) {
try {
@@ -3007,5 +3021,27 @@
throw new RuntimeException(e);
}
}
+
+ /**
+ * Override default audio sink from audio policy.
+ *
+ * @param device {@link android.media.AudioDeviceInfo} to use.
+ * @param samplingRate desired sampling rate. Use default when it's 0.
+ * @param channelMask desired channel mask. Use default when it's
+ * AudioFormat.CHANNEL_OUT_DEFAULT.
+ * @param format desired format. Use default when it's AudioFormat.ENCODING_DEFAULT.
+ */
+ public void overrideAudioSink(@NonNull AudioDeviceInfo device,
+ @IntRange(from = 0) int samplingRate,
+ int channelMask, @Encoding int format) {
+ Objects.requireNonNull(device);
+ try {
+ mInterface.overrideAudioSink(
+ AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()),
+ device.getAddress(), samplingRate, channelMask, format);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/SmartStorageMaintIdler.java b/services/core/java/com/android/server/SmartStorageMaintIdler.java
new file mode 100644
index 0000000..2dff72f
--- /dev/null
+++ b/services/core/java/com/android/server/SmartStorageMaintIdler.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 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.util.Slog;
+
+import java.util.concurrent.TimeUnit;
+
+public class SmartStorageMaintIdler extends JobService {
+ private static final String TAG = "SmartStorageMaintIdler";
+
+ private static final ComponentName SMART_STORAGE_MAINT_SERVICE =
+ new ComponentName("android", SmartStorageMaintIdler.class.getName());
+
+ private static final int SMART_MAINT_JOB_ID = 2808;
+
+ private boolean mStarted;
+ private JobParameters mJobParams;
+ private final Runnable mFinishCallback = new Runnable() {
+ @Override
+ public void run() {
+ Slog.i(TAG, "Got smart storage maintenance service completion callback");
+ if (mStarted) {
+ jobFinished(mJobParams, false);
+ mStarted = false;
+ }
+ // ... and try again in a next period
+ scheduleSmartIdlePass(SmartStorageMaintIdler.this,
+ StorageManagerService.SMART_IDLE_MAINT_PERIOD);
+ }
+ };
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ mJobParams = params;
+ StorageManagerService ms = StorageManagerService.sSelf;
+ if (ms != null) {
+ mStarted = true;
+ ms.runSmartIdleMaint(mFinishCallback);
+ }
+ return ms != null;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ mStarted = false;
+ return false;
+ }
+
+ /**
+ * Schedule the smart storage idle maintenance job
+ */
+ public static void scheduleSmartIdlePass(Context context, int nHours) {
+ StorageManagerService ms = StorageManagerService.sSelf;
+ if ((ms == null) || ms.isPassedLifetimeThresh()) {
+ return;
+ }
+
+ JobScheduler tm = context.getSystemService(JobScheduler.class);
+
+ long nextScheduleTime = TimeUnit.HOURS.toMillis(nHours);
+
+ JobInfo.Builder builder = new JobInfo.Builder(SMART_MAINT_JOB_ID,
+ SMART_STORAGE_MAINT_SERVICE);
+
+ builder.setMinimumLatency(nextScheduleTime);
+ tm.schedule(builder.build());
+ }
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 2d6170b..53c8635 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -79,6 +79,7 @@
import android.content.res.ObbInfo;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.BatteryManager;
import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
@@ -158,6 +159,8 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -339,7 +342,44 @@
@Nullable public static String sMediaStoreAuthorityProcessName;
+ // Run period in hour for smart idle maintenance
+ static final int SMART_IDLE_MAINT_PERIOD = 1;
+
private final AtomicFile mSettingsFile;
+ private final AtomicFile mHourlyWriteFile;
+
+ private static final int MAX_HOURLY_WRITE_RECORDS = 72;
+
+ /**
+ * Default config values for smart idle maintenance
+ * Actual values will be controlled by DeviceConfig
+ */
+ // Decide whether smart idle maintenance is enabled or not
+ private static final boolean DEFAULT_SMART_IDLE_MAINT_ENABLED = false;
+ // Storage lifetime percentage threshold to decide to turn off the feature
+ private static final int DEFAULT_LIFETIME_PERCENT_THRESHOLD = 70;
+ // Minimum required number of dirty + free segments to trigger GC
+ private static final int DEFAULT_MIN_SEGMENTS_THRESHOLD = 512;
+ // Determine how much portion of current dirty segments will be GCed
+ private static final float DEFAULT_DIRTY_RECLAIM_RATE = 0.5F;
+ // Multiplier to amplify the target segment number for GC
+ private static final float DEFAULT_SEGMENT_RECLAIM_WEIGHT = 1.0F;
+ // Low battery level threshold to decide to turn off the feature
+ private static final float DEFAULT_LOW_BATTERY_LEVEL = 20F;
+ // Decide whether charging is required to turn on the feature
+ private static final boolean DEFAULT_CHARGING_REQUIRED = true;
+
+ private volatile int mLifetimePercentThreshold;
+ private volatile int mMinSegmentsThreshold;
+ private volatile float mDirtyReclaimRate;
+ private volatile float mSegmentReclaimWeight;
+ private volatile float mLowBatteryLevel;
+ private volatile boolean mChargingRequired;
+ private volatile boolean mNeedGC;
+
+ private volatile boolean mPassedLifetimeThresh;
+ // Tracking storage hourly write amounts
+ private volatile int[] mStorageHourlyWrites;
/**
* <em>Never</em> hold the lock while performing downcalls into vold, since
@@ -901,6 +941,10 @@
}
private void handleSystemReady() {
+ if (prepareSmartIdleMaint()) {
+ SmartStorageMaintIdler.scheduleSmartIdlePass(mContext, SMART_IDLE_MAINT_PERIOD);
+ }
+
// Start scheduling nominally-daily fstrim operations
MountServiceIdler.scheduleIdlePass(mContext);
@@ -1907,6 +1951,10 @@
mSettingsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "storage.xml"), "storage-settings");
+ mHourlyWriteFile = new AtomicFile(
+ new File(Environment.getDataSystemDirectory(), "storage-hourly-writes"));
+
+ mStorageHourlyWrites = new int[MAX_HOURLY_WRITE_RECORDS];
synchronized (mLock) {
readSettingsLocked();
@@ -2572,7 +2620,7 @@
// fstrim time is still updated. If file based checkpoints are used, we run
// idle maintenance (GC + fstrim) regardless of checkpoint status.
if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
- mVold.runIdleMaint(new IVoldTaskListener.Stub() {
+ mVold.runIdleMaint(mNeedGC, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
// Not currently used
@@ -2623,6 +2671,176 @@
abortIdleMaint(null);
}
+ private boolean prepareSmartIdleMaint() {
+ /**
+ * We can choose whether going with a new storage smart idle maintenance job
+ * or falling back to the traditional way using DeviceConfig
+ */
+ boolean smartIdleMaintEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "smart_idle_maint_enabled",
+ DEFAULT_SMART_IDLE_MAINT_ENABLED);
+ if (smartIdleMaintEnabled) {
+ mLifetimePercentThreshold = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "lifetime_threshold", DEFAULT_LIFETIME_PERCENT_THRESHOLD);
+ mMinSegmentsThreshold = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "min_segments_threshold", DEFAULT_MIN_SEGMENTS_THRESHOLD);
+ mDirtyReclaimRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "dirty_reclaim_rate", DEFAULT_DIRTY_RECLAIM_RATE);
+ mSegmentReclaimWeight = DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "segment_reclaim_weight", DEFAULT_SEGMENT_RECLAIM_WEIGHT);
+ mLowBatteryLevel = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "low_battery_level", DEFAULT_LOW_BATTERY_LEVEL);
+ mChargingRequired = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "charging_required", DEFAULT_CHARGING_REQUIRED);
+
+ // If we use the smart idle maintenance, we need to turn off GC in the traditional idle
+ // maintenance to avoid the conflict
+ mNeedGC = false;
+
+ loadStorageHourlyWrites();
+ try {
+ mVold.refreshLatestWrite();
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ refreshLifetimeConstraint();
+ }
+ return smartIdleMaintEnabled;
+ }
+
+ // Return whether storage lifetime exceeds the threshold
+ public boolean isPassedLifetimeThresh() {
+ return mPassedLifetimeThresh;
+ }
+
+ private void loadStorageHourlyWrites() {
+ FileInputStream fis = null;
+
+ try {
+ fis = mHourlyWriteFile.openRead();
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ mStorageHourlyWrites = (int[])ois.readObject();
+ } catch (FileNotFoundException e) {
+ // Missing data is okay, probably first boot
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Failed reading write records", e);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ }
+ }
+
+ private int getAverageHourlyWrite() {
+ return Arrays.stream(mStorageHourlyWrites).sum() / MAX_HOURLY_WRITE_RECORDS;
+ }
+
+ private void updateStorageHourlyWrites(int latestWrite) {
+ FileOutputStream fos = null;
+
+ System.arraycopy(mStorageHourlyWrites,0, mStorageHourlyWrites, 1,
+ MAX_HOURLY_WRITE_RECORDS - 1);
+ mStorageHourlyWrites[0] = latestWrite;
+ try {
+ fos = mHourlyWriteFile.startWrite();
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ oos.writeObject(mStorageHourlyWrites);
+ mHourlyWriteFile.finishWrite(fos);
+ } catch (IOException e) {
+ if (fos != null) {
+ mHourlyWriteFile.failWrite(fos);
+ }
+ }
+ }
+
+ private boolean checkChargeStatus() {
+ IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ Intent batteryStatus = mContext.registerReceiver(null, ifilter);
+
+ if (mChargingRequired) {
+ int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+ if (status != BatteryManager.BATTERY_STATUS_CHARGING &&
+ status != BatteryManager.BATTERY_STATUS_FULL) {
+ Slog.w(TAG, "Battery is not being charged");
+ return false;
+ }
+ }
+
+ int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+ int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+ float chargePercent = level * 100f / (float)scale;
+
+ if (chargePercent < mLowBatteryLevel) {
+ Slog.w(TAG, "Battery level is " + chargePercent + ", which is lower than threshold: " +
+ mLowBatteryLevel);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean refreshLifetimeConstraint() {
+ int storageLifeTime = 0;
+
+ try {
+ storageLifeTime = mVold.getStorageLifeTime();
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ return false;
+ }
+
+ if (storageLifeTime == -1) {
+ Slog.w(TAG, "Failed to get storage lifetime");
+ return false;
+ } else if (storageLifeTime > mLifetimePercentThreshold) {
+ Slog.w(TAG, "Ended smart idle maintenance, because of lifetime(" + storageLifeTime +
+ ")" + ", lifetime threshold(" + mLifetimePercentThreshold + ")");
+ mPassedLifetimeThresh = true;
+ return false;
+ }
+ Slog.i(TAG, "Storage lifetime: " + storageLifeTime);
+ return true;
+ }
+
+ void runSmartIdleMaint(Runnable callback) {
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+
+ try {
+ // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
+ // (first boot after OTA), We skip the smart idle maintenance
+ if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
+ if (!refreshLifetimeConstraint() || !checkChargeStatus()) {
+ return;
+ }
+
+ int latestHourlyWrite = mVold.getWriteAmount();
+ if (latestHourlyWrite == -1) {
+ Slog.w(TAG, "Failed to get storage hourly write");
+ return;
+ }
+
+ updateStorageHourlyWrites(latestHourlyWrite);
+ int avgHourlyWrite = getAverageHourlyWrite();
+
+ Slog.i(TAG, "Set smart idle maintenance: " + "latest hourly write: " +
+ latestHourlyWrite + ", average hourly write: " + avgHourlyWrite +
+ ", min segment threshold: " + mMinSegmentsThreshold +
+ ", dirty reclaim rate: " + mDirtyReclaimRate +
+ ", segment reclaim weight:" + mSegmentReclaimWeight);
+ mVold.setGCUrgentPace(avgHourlyWrite, mMinSegmentsThreshold, mDirtyReclaimRate,
+ mSegmentReclaimWeight);
+ } else {
+ Slog.i(TAG, "Skipping smart idle maintenance - block based checkpoint in progress");
+ }
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ } finally {
+ if (callback != null) {
+ callback.run();
+ }
+ }
+ }
+
@Override
public void setDebugFlags(int flags, int mask) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0792d9b..df98390 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -231,6 +231,7 @@
import android.net.ConnectivityManager;
import android.net.ConnectivitySettingsManager;
import android.net.IIpConnectivityMetrics;
+import android.net.ProfileNetworkPreference;
import android.net.ProxyInfo;
import android.net.Uri;
import android.net.VpnManager;
@@ -17538,10 +17539,14 @@
}
int networkPreference = preferentialNetworkServiceEnabled
? PROFILE_NETWORK_PREFERENCE_ENTERPRISE : PROFILE_NETWORK_PREFERENCE_DEFAULT;
+ ProfileNetworkPreference.Builder preferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ preferenceBuilder.setPreference(networkPreference);
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceBuilder.build());
mInjector.binderWithCleanCallingIdentity(() ->
- mInjector.getConnectivityManager().setProfileNetworkPreference(
- UserHandle.of(userId),
- networkPreference,
+ mInjector.getConnectivityManager().setProfileNetworkPreferences(
+ UserHandle.of(userId), preferences,
null /* executor */, null /* listener */));
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 3ac30d02..a63aa6a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -37,6 +37,8 @@
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.PasswordMetrics.computeForPasswordOrPin;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.InetAddresses.parseNumericAddress;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
@@ -99,7 +101,7 @@
import android.content.pm.UserInfo;
import android.graphics.Color;
import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
+import android.net.ProfileNetworkPreference;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -4044,12 +4046,15 @@
mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);
dpms.handleStartUser(managedProfileUserId);
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- anyInt(),
- any(),
- any()
- );
+ ProfileNetworkPreference preferenceDetails =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
+ .build();
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+ null, null);
}
@Test
@@ -4061,12 +4066,15 @@
mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);
dpms.handleStopUser(managedProfileUserId);
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT),
- any(),
- any()
- );
+ ProfileNetworkPreference preferenceDetails =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
+ .build();
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+ null, null);
}
@Test
@@ -4084,21 +4092,29 @@
dpm.setPreferentialNetworkServiceEnabled(false);
assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT),
- any(),
- any()
- );
+
+ ProfileNetworkPreference preferenceDetails =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
+ .build();
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+ null, null);
dpm.setPreferentialNetworkServiceEnabled(true);
assertThat(dpm.isPreferentialNetworkServiceEnabled()).isTrue();
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE),
- any(),
- any()
- );
+
+ ProfileNetworkPreference preferenceDetails2 =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE)
+ .build();
+ List<ProfileNetworkPreference> preferences2 = new ArrayList<>();
+ preferences2.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences2,
+ null, null);
}
@Test
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index ba95841..39ab7eb 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -592,6 +592,7 @@
int RIL_UNSOL_UNTHROTTLE_APN = 1052;
int RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED = 1053;
int RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED = 1054;
+ int RIL_UNSOL_SLICING_CONFIG_CHANGED = 1055;
/* The following unsols are not defined in RIL.h */
int RIL_UNSOL_HAL_NON_RIL_BASE = 1100;