Merge "Fix hasUseBackgroundNetworksPermission issue."
diff --git a/Android.bp b/Android.bp
index 543e656..5f06a63 100644
--- a/Android.bp
+++ b/Android.bp
@@ -520,24 +520,22 @@
name: "framework-javastream-protos",
depfile: true,
- tool_files: ["tools/genprotos.sh"],
tools: [
"aprotoc",
"protoc-gen-javastream",
"soong_zip",
],
- // TODO This should not be needed. If you set a custom OUT_DIR or OUT_DIR_COMMON_BASE you can
- // end up with a command that is extremely long, potentially going passed MAX_ARG_STRLEN due to
- // the way sbox rewrites the command. See b/70221552.
- cmd: "$(location tools/genprotos.sh) " +
- " $(location aprotoc) " +
- " $(location protoc-gen-javastream) " +
- " $(location soong_zip) " +
- " $(genDir) " +
- " $(depfile) " +
- " $(in) " +
- " $(out)",
+ cmd: "mkdir -p $(genDir)/$(in) " +
+ "&& $(location aprotoc) " +
+ " --plugin=$(location protoc-gen-javastream) " +
+ " --dependency_out=$(depfile) " +
+ " --javastream_out=$(genDir)/$(in) " +
+ " -Iexternal/protobuf/src " +
+ " -I . " +
+ " $(in) " +
+ "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
@@ -818,11 +816,13 @@
srcs: [
"core/java/android/os/HidlSupport.java",
"core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
"core/java/android/annotation/UnsupportedAppUsage.java",
+ "core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
@@ -897,7 +897,10 @@
"-overview $(location core/java/overview.html) " +
// Federate Support Library references against local API file.
"-federate SupportLib https://developer.android.com " +
- "-federationapi SupportLib $(location :current-support-api) "
+ "-federationapi SupportLib $(location :current-support-api) " +
+ // Federate Support Library references against local API file.
+ "-federate AndroidX https://developer.android.com " +
+ "-federationapi AndroidX $(location :current-androidx-api) "
framework_docs_only_libs = [
"voip-common",
@@ -1015,6 +1018,7 @@
"core/res/AndroidManifest.xml",
"core/java/overview.html",
":current-support-api",
+ ":current-androidx-api",
],
create_stubs: false,
}
@@ -1034,6 +1038,7 @@
":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
+ ":ike-api-srcs",
],
libs: ["framework-internal-utils"],
installable: false,
@@ -1356,8 +1361,10 @@
srcs: [
"core/java/android/os/HidlSupport.java",
"core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/SystemApi.java",
+ "core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
diff --git a/api/current.txt b/api/current.txt
index ca692b0..5098324 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3021,9 +3021,9 @@
field public final String type;
}
- public class AccountAuthenticatorActivity extends android.app.Activity {
- ctor public AccountAuthenticatorActivity();
- method public final void setAccountAuthenticatorResult(android.os.Bundle);
+ @Deprecated public class AccountAuthenticatorActivity extends android.app.Activity {
+ ctor @Deprecated public AccountAuthenticatorActivity();
+ method @Deprecated public final void setAccountAuthenticatorResult(android.os.Bundle);
}
public class AccountAuthenticatorResponse implements android.os.Parcelable {
@@ -4698,18 +4698,18 @@
field public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3; // 0x3
}
- public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener {
- ctor public ExpandableListActivity();
- method public android.widget.ExpandableListAdapter getExpandableListAdapter();
- method public android.widget.ExpandableListView getExpandableListView();
- method public long getSelectedId();
- method public long getSelectedPosition();
- method public boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long);
- method public void onGroupCollapse(int);
- method public void onGroupExpand(int);
- method public void setListAdapter(android.widget.ExpandableListAdapter);
- method public boolean setSelectedChild(int, int, boolean);
- method public void setSelectedGroup(int);
+ @Deprecated public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener {
+ ctor @Deprecated public ExpandableListActivity();
+ method @Deprecated public android.widget.ExpandableListAdapter getExpandableListAdapter();
+ method @Deprecated public android.widget.ExpandableListView getExpandableListView();
+ method @Deprecated public long getSelectedId();
+ method @Deprecated public long getSelectedPosition();
+ method @Deprecated public boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long);
+ method @Deprecated public void onGroupCollapse(int);
+ method @Deprecated public void onGroupExpand(int);
+ method @Deprecated public void setListAdapter(android.widget.ExpandableListAdapter);
+ method @Deprecated public boolean setSelectedChild(int, int, boolean);
+ method @Deprecated public void setSelectedGroup(int);
}
@Deprecated public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
@@ -5151,40 +5151,40 @@
method @Deprecated public void onKeyguardExitResult(boolean);
}
- public abstract class LauncherActivity extends android.app.ListActivity {
- ctor public LauncherActivity();
- method protected android.content.Intent getTargetIntent();
- method protected android.content.Intent intentForPosition(int);
- method protected android.app.LauncherActivity.ListItem itemForPosition(int);
- method public java.util.List<android.app.LauncherActivity.ListItem> makeListItems();
- method protected java.util.List<android.content.pm.ResolveInfo> onQueryPackageManager(android.content.Intent);
- method protected void onSetContentView();
+ @Deprecated public abstract class LauncherActivity extends android.app.ListActivity {
+ ctor @Deprecated public LauncherActivity();
+ method @Deprecated protected android.content.Intent getTargetIntent();
+ method @Deprecated protected android.content.Intent intentForPosition(int);
+ method @Deprecated protected android.app.LauncherActivity.ListItem itemForPosition(int);
+ method @Deprecated public java.util.List<android.app.LauncherActivity.ListItem> makeListItems();
+ method @Deprecated protected java.util.List<android.content.pm.ResolveInfo> onQueryPackageManager(android.content.Intent);
+ method @Deprecated protected void onSetContentView();
}
- public class LauncherActivity.IconResizer {
- ctor public LauncherActivity.IconResizer();
- method public android.graphics.drawable.Drawable createIconThumbnail(android.graphics.drawable.Drawable);
+ @Deprecated public class LauncherActivity.IconResizer {
+ ctor @Deprecated public LauncherActivity.IconResizer();
+ method @Deprecated public android.graphics.drawable.Drawable createIconThumbnail(android.graphics.drawable.Drawable);
}
- public static class LauncherActivity.ListItem {
- ctor public LauncherActivity.ListItem();
- field public String className;
- field public android.os.Bundle extras;
- field public android.graphics.drawable.Drawable icon;
- field public CharSequence label;
- field public String packageName;
- field public android.content.pm.ResolveInfo resolveInfo;
+ @Deprecated public static class LauncherActivity.ListItem {
+ ctor @Deprecated public LauncherActivity.ListItem();
+ field @Deprecated public String className;
+ field @Deprecated public android.os.Bundle extras;
+ field @Deprecated public android.graphics.drawable.Drawable icon;
+ field @Deprecated public CharSequence label;
+ field @Deprecated public String packageName;
+ field @Deprecated public android.content.pm.ResolveInfo resolveInfo;
}
- public class ListActivity extends android.app.Activity {
- ctor public ListActivity();
- method public android.widget.ListAdapter getListAdapter();
- method public android.widget.ListView getListView();
- method public long getSelectedItemId();
- method public int getSelectedItemPosition();
- method protected void onListItemClick(android.widget.ListView, android.view.View, int, long);
- method public void setListAdapter(android.widget.ListAdapter);
- method public void setSelection(int);
+ @Deprecated public class ListActivity extends android.app.Activity {
+ ctor @Deprecated public ListActivity();
+ method @Deprecated public android.widget.ListAdapter getListAdapter();
+ method @Deprecated public android.widget.ListView getListView();
+ method @Deprecated public long getSelectedItemId();
+ method @Deprecated public int getSelectedItemPosition();
+ method @Deprecated protected void onListItemClick(android.widget.ListView, android.view.View, int, long);
+ method @Deprecated public void setListAdapter(android.widget.ListAdapter);
+ method @Deprecated public void setSelection(int);
}
@Deprecated public class ListFragment extends android.app.Fragment {
@@ -5552,6 +5552,7 @@
method @Deprecated public android.app.Notification.Builder setDefaults(int);
method @NonNull public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method @NonNull public android.app.Notification.Builder setExtras(android.os.Bundle);
+ method @NonNull public android.app.Notification.Builder setFlag(int, boolean);
method @NonNull public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
method @NonNull public android.app.Notification.Builder setGroup(String);
method @NonNull public android.app.Notification.Builder setGroupAlertBehavior(int);
@@ -9771,7 +9772,7 @@
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String);
method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
- method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+ method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -28935,14 +28936,17 @@
}
public class ProxyInfo implements android.os.Parcelable {
+ ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
method public static android.net.ProxyInfo buildDirectProxy(String, int);
method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+ method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
method public int describeContents();
method public String[] getExclusionList();
method public String getHost();
method public android.net.Uri getPacFileUrl();
method public int getPort();
+ method public boolean isValid();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
}
@@ -29891,6 +29895,7 @@
field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
field @Deprecated public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
field @Deprecated public static final String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+ field public static final String UNKNOWN_SSID = "<unknown ssid>";
field @Deprecated public static final int WIFI_MODE_FULL = 1; // 0x1
field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
field public static final int WIFI_MODE_FULL_LOW_LATENCY = 4; // 0x4
@@ -34535,8 +34540,8 @@
}
public final class FileUtils {
- method public static void closeQuietly(@Nullable AutoCloseable);
- method public static void closeQuietly(@Nullable java.io.FileDescriptor);
+ method @Deprecated public static void closeQuietly(@Nullable AutoCloseable);
+ method @Deprecated public static void closeQuietly(@Nullable java.io.FileDescriptor);
method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream) throws java.io.IOException;
method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @Nullable android.os.FileUtils.ProgressListener) throws java.io.IOException;
method public static long copy(@NonNull java.io.FileDescriptor, @NonNull java.io.FileDescriptor) throws java.io.IOException;
@@ -34548,8 +34553,8 @@
}
public class Handler {
- ctor public Handler();
- ctor public Handler(@Nullable android.os.Handler.Callback);
+ ctor @Deprecated public Handler();
+ ctor @Deprecated public Handler(@Nullable android.os.Handler.Callback);
ctor public Handler(@NonNull android.os.Looper);
ctor public Handler(@NonNull android.os.Looper, @Nullable android.os.Handler.Callback);
method @NonNull public static android.os.Handler createAsync(@NonNull android.os.Looper);
@@ -34673,7 +34678,7 @@
method @Nullable public static android.os.Looper myLooper();
method @NonNull public static android.os.MessageQueue myQueue();
method public static void prepare();
- method public static void prepareMainLooper();
+ method @Deprecated public static void prepareMainLooper();
method public void quit();
method public void quitSafely();
method public void setMessageLogging(@Nullable android.util.Printer);
@@ -43520,6 +43525,7 @@
field public static final int LOCAL = 2; // 0x2
field public static final int MISSED = 5; // 0x5
field public static final int OTHER = 9; // 0x9
+ field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
field public static final int REJECTED = 6; // 0x6
field public static final int REMOTE = 3; // 0x3
field public static final int RESTRICTED = 8; // 0x8
@@ -44048,6 +44054,7 @@
field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
+ field public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL = "allow_hold_call_during_emergency_bool";
field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
@@ -48523,12 +48530,12 @@
method @Nullable public static java.util.List<java.lang.String> getTimeZoneIdsForCountryCode(@NonNull String);
}
- public class TimingLogger {
- ctor public TimingLogger(String, String);
- method public void addSplit(String);
- method public void dumpToLog();
- method public void reset(String, String);
- method public void reset();
+ @Deprecated public class TimingLogger {
+ ctor @Deprecated public TimingLogger(String, String);
+ method @Deprecated public void addSplit(String);
+ method @Deprecated public void dumpToLog();
+ method @Deprecated public void reset(String, String);
+ method @Deprecated public void reset();
}
public class TypedValue {
diff --git a/api/system-current.txt b/api/system-current.txt
index 34be264..0b8cdf2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -66,6 +66,7 @@
field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
+ field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
@@ -74,6 +75,7 @@
field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
+ field public static final String HANDLE_CAR_MODE_CHANGES = "android.permission.HANDLE_CAR_MODE_CHANGES";
field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
field public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
@@ -602,6 +604,15 @@
method public boolean isStatusBarExpansionDisabled();
}
+ public class UiModeManager {
+ method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
+ field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
+ field public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
+ field public static final int DEFAULT_PRIORITY = 0; // 0x0
+ field public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE";
+ field public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY";
+ }
+
public final class Vr2dDisplayProperties implements android.os.Parcelable {
ctor public Vr2dDisplayProperties(int, int, int);
method public int describeContents();
@@ -1300,7 +1311,23 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
}
+ public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
+ method protected void finalize();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
+ method public boolean isTetheringOn();
+ method public void setBluetoothTethering(boolean);
+ field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+ field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ field public static final int LOCAL_NAP_ROLE = 1; // 0x1
+ field public static final int LOCAL_PANU_ROLE = 2; // 0x2
+ field public static final int PAN_ROLE_NONE = 0; // 0x0
+ field public static final int REMOTE_NAP_ROLE = 1; // 0x1
+ field public static final int REMOTE_PANU_ROLE = 2; // 0x2
+ }
+
public interface BluetoothProfile {
+ field public static final int PAN = 5; // 0x5
field public static final int PRIORITY_OFF = 0; // 0x0
field public static final int PRIORITY_ON = 100; // 0x64
}
@@ -1355,8 +1382,9 @@
public abstract class Context {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean bindServiceAsUser(@RequiresPermission android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
+ method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
method public abstract android.content.Context createCredentialProtectedStorageContext();
- method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable public abstract java.io.File getPreloadsFileCache();
method public abstract boolean isCredentialProtectedStorage();
method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
@@ -4052,6 +4080,33 @@
method public void onUpstreamChanged(@Nullable android.net.Network);
}
+ public final class IpConfiguration implements android.os.Parcelable {
+ ctor public IpConfiguration();
+ ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
+ method @Nullable public android.net.ProxyInfo getHttpProxy();
+ method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
+ method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+ method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
+ method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+ method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
+ method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
+ method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
+ }
+
+ public enum IpConfiguration.IpAssignment {
+ enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
+ enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
+ enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
+ }
+
+ public enum IpConfiguration.ProxySettings {
+ enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
+ }
+
public final class IpPrefix implements android.os.Parcelable {
ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public IpPrefix(@NonNull String);
@@ -4124,6 +4179,7 @@
public class NetworkKey implements android.os.Parcelable {
ctor public NetworkKey(android.net.WifiKey);
+ method @Nullable public static android.net.NetworkKey createFromScanResult(@Nullable android.net.wifi.ScanResult);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR;
@@ -4146,16 +4202,23 @@
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean clearScores() throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public void disableScoring() throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public String getActiveScorerPackage();
+ method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
+ method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public boolean requestScores(@NonNull android.net.NetworkKey[]) throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
- method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException;
- field public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
+ method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException;
+ field @Deprecated public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
field public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
field public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
- field public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
- field public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
+ field @Deprecated public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
+ field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
field public static final String EXTRA_NEW_SCORER = "newScorer";
- field public static final String EXTRA_PACKAGE_NAME = "packageName";
+ field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName";
+ }
+
+ public static interface NetworkScoreManager.NetworkScoreCallback {
+ method public void clearScores();
+ method public void updateScores(@NonNull java.util.List<android.net.ScoredNetwork>);
}
public class NetworkStack {
@@ -4277,6 +4340,258 @@
}
+package android.net.eap {
+
+ public final class EapSessionConfig {
+ }
+
+ public static final class EapSessionConfig.Builder {
+ ctor public EapSessionConfig.Builder();
+ method @NonNull public android.net.eap.EapSessionConfig build();
+ method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaConfig(int, int);
+ method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaPrimeConfig(int, int, @NonNull String, boolean);
+ method @NonNull public android.net.eap.EapSessionConfig.Builder setEapIdentity(@NonNull byte[]);
+ method @NonNull public android.net.eap.EapSessionConfig.Builder setEapMsChapV2Config(@NonNull String, @NonNull String);
+ method @NonNull public android.net.eap.EapSessionConfig.Builder setEapSimConfig(int, int);
+ }
+
+ public static class EapSessionConfig.EapAkaConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
+ }
+
+ public static class EapSessionConfig.EapAkaPrimeConfig extends android.net.eap.EapSessionConfig.EapAkaConfig {
+ method public boolean allowsMismatchedNetworkNames();
+ method @NonNull public String getNetworkName();
+ }
+
+ public abstract static class EapSessionConfig.EapMethodConfig {
+ method public int getMethodType();
+ }
+
+ public static class EapSessionConfig.EapMsChapV2Config extends android.net.eap.EapSessionConfig.EapMethodConfig {
+ method @NonNull public String getPassword();
+ method @NonNull public String getUsername();
+ }
+
+ public static class EapSessionConfig.EapSimConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
+ }
+
+ public abstract static class EapSessionConfig.EapUiccConfig extends android.net.eap.EapSessionConfig.EapMethodConfig {
+ method public int getAppType();
+ method public int getSubId();
+ }
+
+}
+
+package android.net.ipsec.ike {
+
+ public final class ChildSaProposal extends android.net.ipsec.ike.SaProposal {
+ }
+
+ public static final class ChildSaProposal.Builder {
+ ctor public ChildSaProposal.Builder();
+ method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addDhGroup(int);
+ method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addEncryptionAlgorithm(int, int);
+ method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addIntegrityAlgorithm(int);
+ method @NonNull public android.net.ipsec.ike.ChildSaProposal build();
+ }
+
+ public interface ChildSessionCallback {
+ method public void onClosed();
+ method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
+ method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int);
+ method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int);
+ method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration);
+ }
+
+ public final class ChildSessionConfiguration {
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getInboundTrafficSelectors();
+ method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses();
+ method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers();
+ method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers();
+ method @NonNull public java.util.List<android.net.LinkAddress> getInternalSubnets();
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
+ }
+
+ public abstract class ChildSessionOptions {
+ }
+
+ public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
+ ctor public IkeFqdnIdentification(@NonNull String);
+ field @NonNull public final String fqdn;
+ }
+
+ public abstract class IkeIdentification {
+ }
+
+ public final class IkeIpv4AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
+ ctor public IkeIpv4AddrIdentification(@NonNull java.net.Inet4Address);
+ field @NonNull public final java.net.Inet4Address ipv4Address;
+ }
+
+ public class IkeIpv6AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
+ ctor public IkeIpv6AddrIdentification(@NonNull java.net.Inet6Address);
+ field @NonNull public final java.net.Inet6Address ipv6Address;
+ }
+
+ public final class IkeKeyIdIdentification extends android.net.ipsec.ike.IkeIdentification {
+ ctor public IkeKeyIdIdentification(@NonNull byte[]);
+ field @NonNull public final byte[] keyId;
+ }
+
+ public final class IkeRfc822AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
+ ctor public IkeRfc822AddrIdentification(@NonNull String);
+ field @NonNull public final String rfc822Name;
+ }
+
+ public final class IkeSaProposal extends android.net.ipsec.ike.SaProposal {
+ method @NonNull public java.util.List<java.lang.Integer> getPseudorandomFunctions();
+ }
+
+ public static final class IkeSaProposal.Builder {
+ ctor public IkeSaProposal.Builder();
+ method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addDhGroup(int);
+ method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addEncryptionAlgorithm(int, int);
+ method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addIntegrityAlgorithm(int);
+ method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addPseudorandomFunction(int);
+ method @NonNull public android.net.ipsec.ike.IkeSaProposal build();
+ }
+
+ public final class IkeSession implements java.lang.AutoCloseable {
+ ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+ method public void close();
+ method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback);
+ method public void kill();
+ method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+ }
+
+ public interface IkeSessionCallback {
+ method public void onClosed();
+ method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
+ method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException);
+ method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration);
+ }
+
+ public final class IkeSessionConfiguration {
+ ctor public IkeSessionConfiguration();
+ method @NonNull public String getRemoteApplicationVersion();
+ method public boolean isIkeExtensionEnabled(int);
+ field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1
+ field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
+ }
+
+ public final class IkeSessionOptions {
+ }
+
+ public static final class IkeSessionOptions.Builder {
+ ctor public IkeSessionOptions.Builder();
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions build();
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthPsk(@NonNull byte[]);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setServerAddress(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
+ }
+
+ public final class IkeTrafficSelector {
+ ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
+ field public final int endPort;
+ field @NonNull public final java.net.InetAddress endingAddress;
+ field public final int startPort;
+ field @NonNull public final java.net.InetAddress startingAddress;
+ }
+
+ public abstract class SaProposal {
+ method @NonNull public java.util.List<java.lang.Integer> getDhGroups();
+ method @NonNull public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getEncryptionAlgorithms();
+ method @NonNull public java.util.List<java.lang.Integer> getIntegrityAlgorithms();
+ field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
+ field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
+ field public static final int DH_GROUP_NONE = 0; // 0x0
+ field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3
+ field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
+ field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13
+ field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14
+ field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12
+ field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
+ field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
+ field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
+ field public static final int KEY_LEN_AES_128 = 128; // 0x80
+ field public static final int KEY_LEN_AES_192 = 192; // 0xc0
+ field public static final int KEY_LEN_AES_256 = 256; // 0x100
+ field public static final int KEY_LEN_UNUSED = 0; // 0x0
+ field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
+ field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
+ }
+
+ public final class TransportModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+ }
+
+ public static final class TransportModeChildSessionOptions.Builder {
+ ctor public TransportModeChildSessionOptions.Builder();
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions build();
+ }
+
+ public final class TunnelModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+ }
+
+ public static final class TunnelModeChildSessionOptions.Builder {
+ ctor public TunnelModeChildSessionOptions.Builder();
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalSubnetRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions build();
+ }
+
+}
+
+package android.net.ipsec.ike.exceptions {
+
+ public abstract class IkeException extends java.lang.Exception {
+ }
+
+ public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException {
+ }
+
+ public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException {
+ method @Nullable public byte[] getErrorData();
+ method public int getErrorType();
+ field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18
+ field public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; // 0x2c
+ field public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; // 0x25
+ field public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; // 0x24
+ field public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; // 0x4
+ field public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; // 0x11
+ field public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; // 0x5
+ field public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; // 0x9
+ field public static final int ERROR_TYPE_INVALID_SELECTORS = 39; // 0x27
+ field public static final int ERROR_TYPE_INVALID_SYNTAX = 7; // 0x7
+ field public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; // 0x23
+ field public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; // 0xe
+ field public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; // 0x22
+ field public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; // 0x2b
+ field public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; // 0x26
+ field public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; // 0x1
+ }
+
+}
+
package android.net.metrics {
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -4708,7 +5023,7 @@
method public boolean isPortableHotspotSupported();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
- method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback, @Nullable java.util.concurrent.Executor);
+ method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
@@ -5207,6 +5522,17 @@
method @NonNull public static java.io.File getVendorDirectory();
}
+ public class HidlMemory implements java.io.Closeable {
+ ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+ method public void close() throws java.io.IOException;
+ method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+ method protected void finalize();
+ method @Nullable public android.os.NativeHandle getHandle();
+ method @NonNull public String getName();
+ method public long getSize();
+ method @NonNull public android.os.NativeHandle releaseHandle();
+ }
+
public class HidlSupport {
method public static boolean deepEquals(Object, Object);
method public static int deepHashCode(Object);
@@ -5237,6 +5563,7 @@
method public final void copyToInt8Array(long, byte[], int);
method public final boolean getBool(long);
method public final double getDouble(long);
+ method public final long getFieldHandle(long);
method public final float getFloat(long);
method public final short getInt16(long);
method public final int getInt32(long);
@@ -5251,6 +5578,7 @@
method public final void putDoubleArray(long, double[]);
method public final void putFloat(long, float);
method public final void putFloatArray(long, float[]);
+ method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
method public final void putInt16(long, short);
method public final void putInt16Array(long, short[]);
method public final void putInt32(long, int);
@@ -5279,9 +5607,11 @@
method public final double readDouble();
method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+ method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
method public final float readFloat();
method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+ method @NonNull public final android.os.HidlMemory readHidlMemory();
method public final short readInt16();
method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
method public final int readInt32();
@@ -5306,6 +5636,7 @@
method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
method public final void writeFloat(float);
method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+ method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
method public final void writeInt16(short);
method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
method public final void writeInt32(int);
@@ -7314,6 +7645,21 @@
method @NonNull public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int);
}
+ public class CbGeoUtils {
+ }
+
+ public static interface CbGeoUtils.Geometry {
+ method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
+ }
+
+ public static class CbGeoUtils.LatLng {
+ ctor public CbGeoUtils.LatLng(double, double);
+ method public double distance(@NonNull android.telephony.CbGeoUtils.LatLng);
+ method @NonNull public android.telephony.CbGeoUtils.LatLng subtract(@NonNull android.telephony.CbGeoUtils.LatLng);
+ field public final double lat;
+ field public final double lng;
+ }
+
public abstract class CellBroadcastService extends android.app.Service {
ctor public CellBroadcastService();
method @CallSuper @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent);
@@ -7737,6 +8083,7 @@
field public static final int NUMBER_UNREACHABLE = 8; // 0x8
field public static final int OTASP_PROVISIONING_IN_PROCESS = 76; // 0x4c
field public static final int OUTGOING_CANCELED = 44; // 0x2c
+ field public static final int OUTGOING_EMERGENCY_CALL_PLACED = 80; // 0x50
field public static final int OUTGOING_FAILURE = 43; // 0x2b
field public static final int OUT_OF_NETWORK = 11; // 0xb
field public static final int OUT_OF_SERVICE = 18; // 0x12
@@ -7751,6 +8098,14 @@
field public static final int WIFI_LOST = 59; // 0x3b
}
+ public final class ImsiEncryptionInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getKeyIdentifier();
+ method @Nullable public java.security.PublicKey getPublicKey();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ImsiEncryptionInfo> CREATOR;
+ }
+
public final class LteVopsSupportInfo implements android.os.Parcelable {
ctor public LteVopsSupportInfo(int, int);
method public int describeContents();
@@ -8106,6 +8461,7 @@
}
public final class SmsCbLocation implements android.os.Parcelable {
+ ctor public SmsCbLocation(@NonNull String, int, int);
method public int describeContents();
method public int getCid();
method public int getLac();
@@ -8117,7 +8473,7 @@
}
public final class SmsCbMessage implements android.os.Parcelable {
- ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int);
+ ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int, @Nullable java.util.List<android.telephony.CbGeoUtils.Geometry>, long, int);
method @NonNull public static android.telephony.SmsCbMessage createFromCursor(@NonNull android.database.Cursor);
method public int describeContents();
method @Nullable public android.telephony.SmsCbCmasInfo getCmasWarningInfo();
@@ -8126,6 +8482,7 @@
method public int getGeographicalScope();
method @Nullable public String getLanguageCode();
method @NonNull public android.telephony.SmsCbLocation getLocation();
+ method public int getMaximumWaitingDuration();
method @Nullable public String getMessageBody();
method public int getMessageFormat();
method public int getMessagePriority();
@@ -8143,6 +8500,7 @@
field public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; // 0x0
field public static final int GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2; // 0x2
field public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; // 0x1
+ field public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255; // 0xff
field public static final int MESSAGE_FORMAT_3GPP = 1; // 0x1
field public static final int MESSAGE_FORMAT_3GPP2 = 2; // 0x2
field public static final int MESSAGE_PRIORITY_EMERGENCY = 3; // 0x3
@@ -8228,6 +8586,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
@@ -8277,13 +8636,14 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetherApnRequired();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetheringApnRequired();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method public boolean needsOtaServiceProvisioning();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
@@ -8321,6 +8681,8 @@
field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
+ field public static final int KEY_TYPE_EPDG = 1; // 0x1
+ field public static final int KEY_TYPE_WLAN = 2; // 0x2
field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
@@ -8902,7 +9264,7 @@
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
diff --git a/api/test-current.txt b/api/test-current.txt
index 14210e3..d59d15a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -376,6 +376,7 @@
}
public class UiModeManager {
+ method @RequiresPermission("android.permission.ENTER_CAR_MODE_PRIORITIZED") public void enableCarMode(@IntRange(from=0) int, int);
method public boolean isNightModeLocked();
method public boolean isUiModeLocked();
}
@@ -639,7 +640,8 @@
}
public abstract class Context {
- method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
+ method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.view.Display getDisplay();
method public abstract int getDisplayId();
method public android.os.UserHandle getUser();
@@ -692,6 +694,7 @@
method public void setEnableRollback(boolean);
method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+ method public void setRequestDowngrade(boolean);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
}
@@ -793,6 +796,7 @@
}
public final class RollbackManager {
+ method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void blockRollbackManager(long);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
@@ -1722,6 +1726,17 @@
method public static boolean contains(java.io.File, java.io.File);
}
+ public class HidlMemory implements java.io.Closeable {
+ ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+ method public void close() throws java.io.IOException;
+ method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+ method protected void finalize();
+ method @Nullable public android.os.NativeHandle getHandle();
+ method @NonNull public String getName();
+ method public long getSize();
+ method @NonNull public android.os.NativeHandle releaseHandle();
+ }
+
public abstract class HwBinder implements android.os.IHwBinder {
ctor public HwBinder();
method public static final void configureRpcThreadpool(long, boolean);
@@ -1745,6 +1760,7 @@
method public final void copyToInt8Array(long, byte[], int);
method public final boolean getBool(long);
method public final double getDouble(long);
+ method public final long getFieldHandle(long);
method public final float getFloat(long);
method public final short getInt16(long);
method public final int getInt32(long);
@@ -1759,6 +1775,7 @@
method public final void putDoubleArray(long, double[]);
method public final void putFloat(long, float);
method public final void putFloatArray(long, float[]);
+ method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
method public final void putInt16(long, short);
method public final void putInt16Array(long, short[]);
method public final void putInt32(long, int);
@@ -1787,9 +1804,11 @@
method public final double readDouble();
method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+ method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
method public final float readFloat();
method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+ method @NonNull public final android.os.HidlMemory readHidlMemory();
method public final short readInt16();
method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
method public final int readInt32();
@@ -1814,6 +1833,7 @@
method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
method public final void writeFloat(float);
method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+ method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
method public final void writeInt16(short);
method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
method public final void writeInt32(int);
@@ -3230,7 +3250,7 @@
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiModeSetting();
diff --git a/config/OWNERS b/config/OWNERS
new file mode 100644
index 0000000..53f80e6
--- /dev/null
+++ b/config/OWNERS
@@ -0,0 +1,5 @@
+# compat-team@ for changes to hiddenapi files
+per-file hiddenapi-* = andreionea@google.com, atrost@google.com, mathewi@google.com, satayev@google.com
+
+# Escalations:
+per-file hiddenapi-* = bdc@google.com, narayan@google.com
\ No newline at end of file
diff --git a/config/hiddenapi-greylist-max-q.txt b/config/hiddenapi-greylist-max-q.txt
new file mode 100644
index 0000000..f465604
--- /dev/null
+++ b/config/hiddenapi-greylist-max-q.txt
@@ -0,0 +1,704 @@
+Landroid/R$styleable;->ActionBar:[I
+Landroid/R$styleable;->ActionBar_background:I
+Landroid/R$styleable;->ActionBar_backgroundSplit:I
+Landroid/R$styleable;->ActionBar_backgroundStacked:I
+Landroid/R$styleable;->ActionBar_divider:I
+Landroid/R$styleable;->ActionBar_itemPadding:I
+Landroid/R$styleable;->CalendarView:[I
+Landroid/R$styleable;->CalendarView_dateTextAppearance:I
+Landroid/R$styleable;->CalendarView_firstDayOfWeek:I
+Landroid/R$styleable;->CalendarView_focusedMonthDateColor:I
+Landroid/R$styleable;->CalendarView_selectedDateVerticalBar:I
+Landroid/R$styleable;->CalendarView_selectedWeekBackgroundColor:I
+Landroid/R$styleable;->CalendarView_shownWeekCount:I
+Landroid/R$styleable;->CalendarView_showWeekNumber:I
+Landroid/R$styleable;->CalendarView_unfocusedMonthDateColor:I
+Landroid/R$styleable;->CalendarView_weekDayTextAppearance:I
+Landroid/R$styleable;->CalendarView_weekNumberColor:I
+Landroid/R$styleable;->CalendarView_weekSeparatorLineColor:I
+Landroid/R$styleable;->CheckBoxPreference:[I
+Landroid/R$styleable;->CheckedTextView:[I
+Landroid/R$styleable;->CheckedTextView_checkMark:I
+Landroid/R$styleable;->CompoundButton:[I
+Landroid/R$styleable;->CompoundButton_button:I
+Landroid/R$styleable;->ContactsDataKind:[I
+Landroid/R$styleable;->DatePicker:[I
+Landroid/R$styleable;->DialogPreference:[I
+Landroid/R$styleable;->DrawableStates:[I
+Landroid/R$styleable;->ExpandableListView:[I
+Landroid/R$styleable;->FrameLayout_Layout:[I
+Landroid/R$styleable;->HorizontalScrollView:[I
+Landroid/R$styleable;->ImageView:[I
+Landroid/R$styleable;->ImageView_adjustViewBounds:I
+Landroid/R$styleable;->ImageView_baselineAlignBottom:I
+Landroid/R$styleable;->ImageView_cropToPadding:I
+Landroid/R$styleable;->ImageView_maxHeight:I
+Landroid/R$styleable;->ImageView_maxWidth:I
+Landroid/R$styleable;->ImageView_scaleType:I
+Landroid/R$styleable;->ImageView_src:I
+Landroid/R$styleable;->ImageView_tint:I
+Landroid/R$styleable;->Keyboard:[I
+Landroid/R$styleable;->Keyboard_horizontalGap:I
+Landroid/R$styleable;->Keyboard_Key:[I
+Landroid/R$styleable;->Keyboard_keyHeight:I
+Landroid/R$styleable;->Keyboard_keyWidth:I
+Landroid/R$styleable;->Keyboard_Key_codes:I
+Landroid/R$styleable;->Keyboard_Key_iconPreview:I
+Landroid/R$styleable;->Keyboard_Key_isModifier:I
+Landroid/R$styleable;->Keyboard_Key_isRepeatable:I
+Landroid/R$styleable;->Keyboard_Key_isSticky:I
+Landroid/R$styleable;->Keyboard_Key_keyEdgeFlags:I
+Landroid/R$styleable;->Keyboard_Key_keyIcon:I
+Landroid/R$styleable;->Keyboard_Key_keyLabel:I
+Landroid/R$styleable;->Keyboard_Key_keyOutputText:I
+Landroid/R$styleable;->Keyboard_Key_popupCharacters:I
+Landroid/R$styleable;->Keyboard_Key_popupKeyboard:I
+Landroid/R$styleable;->Keyboard_Row:[I
+Landroid/R$styleable;->Keyboard_Row_keyboardMode:I
+Landroid/R$styleable;->Keyboard_Row_rowEdgeFlags:I
+Landroid/R$styleable;->Keyboard_verticalGap:I
+Landroid/R$styleable;->LinearLayout:[I
+Landroid/R$styleable;->LinearLayout_baselineAligned:I
+Landroid/R$styleable;->LinearLayout_baselineAlignedChildIndex:I
+Landroid/R$styleable;->LinearLayout_divider:I
+Landroid/R$styleable;->LinearLayout_dividerPadding:I
+Landroid/R$styleable;->LinearLayout_gravity:I
+Landroid/R$styleable;->LinearLayout_Layout:[I
+Landroid/R$styleable;->LinearLayout_Layout_layout_gravity:I
+Landroid/R$styleable;->LinearLayout_Layout_layout_height:I
+Landroid/R$styleable;->LinearLayout_Layout_layout_weight:I
+Landroid/R$styleable;->LinearLayout_Layout_layout_width:I
+Landroid/R$styleable;->LinearLayout_measureWithLargestChild:I
+Landroid/R$styleable;->LinearLayout_orientation:I
+Landroid/R$styleable;->LinearLayout_showDividers:I
+Landroid/R$styleable;->ListView:[I
+Landroid/R$styleable;->ListView_divider:I
+Landroid/R$styleable;->ListView_dividerHeight:I
+Landroid/R$styleable;->LockPatternView:[I
+Landroid/R$styleable;->NumberPicker:[I
+Landroid/R$styleable;->NumberPicker_solidColor:I
+Landroid/R$styleable;->PopupWindow:[I
+Landroid/R$styleable;->ProgressBar:[I
+Landroid/R$styleable;->ProgressBar_indeterminateDrawable:I
+Landroid/R$styleable;->ProgressBar_indeterminateDuration:I
+Landroid/R$styleable;->ProgressBar_maxHeight:I
+Landroid/R$styleable;->ProgressBar_maxWidth:I
+Landroid/R$styleable;->ProgressBar_minHeight:I
+Landroid/R$styleable;->ProgressBar_minWidth:I
+Landroid/R$styleable;->ProgressBar_progressDrawable:I
+Landroid/R$styleable;->RingtonePreference:[I
+Landroid/R$styleable;->ScrollView:[I
+Landroid/R$styleable;->SearchView:[I
+Landroid/R$styleable;->SeekBar:[I
+Landroid/R$styleable;->SeekBar_thumb:I
+Landroid/R$styleable;->SeekBar_thumbOffset:I
+Landroid/R$styleable;->SlidingDrawer:[I
+Landroid/R$styleable;->SlidingDrawer_allowSingleTap:I
+Landroid/R$styleable;->SlidingDrawer_animateOnClick:I
+Landroid/R$styleable;->SlidingDrawer_bottomOffset:I
+Landroid/R$styleable;->SlidingDrawer_content:I
+Landroid/R$styleable;->SlidingDrawer_handle:I
+Landroid/R$styleable;->SlidingDrawer_orientation:I
+Landroid/R$styleable;->SlidingDrawer_topOffset:I
+Landroid/R$styleable;->Switch:[I
+Landroid/R$styleable;->Switch_showText:I
+Landroid/R$styleable;->Switch_splitTrack:I
+Landroid/R$styleable;->Switch_switchMinWidth:I
+Landroid/R$styleable;->Switch_switchPadding:I
+Landroid/R$styleable;->Switch_switchTextAppearance:I
+Landroid/R$styleable;->Switch_textOff:I
+Landroid/R$styleable;->Switch_textOn:I
+Landroid/R$styleable;->Switch_thumb:I
+Landroid/R$styleable;->Switch_thumbTextPadding:I
+Landroid/R$styleable;->Switch_track:I
+Landroid/R$styleable;->TextAppearance:[I
+Landroid/R$styleable;->TextAppearance_textAllCaps:I
+Landroid/R$styleable;->TextAppearance_textColor:I
+Landroid/R$styleable;->TextAppearance_textColorHighlight:I
+Landroid/R$styleable;->TextAppearance_textColorHint:I
+Landroid/R$styleable;->TextAppearance_textColorLink:I
+Landroid/R$styleable;->TextAppearance_textSize:I
+Landroid/R$styleable;->TextAppearance_textStyle:I
+Landroid/R$styleable;->TextAppearance_typeface:I
+Landroid/R$styleable;->TextView:[I
+Landroid/R$styleable;->TextView_autoLink:I
+Landroid/R$styleable;->TextView_autoText:I
+Landroid/R$styleable;->TextView_bufferType:I
+Landroid/R$styleable;->TextView_capitalize:I
+Landroid/R$styleable;->TextView_cursorVisible:I
+Landroid/R$styleable;->TextView_digits:I
+Landroid/R$styleable;->TextView_drawableBottom:I
+Landroid/R$styleable;->TextView_drawableEnd:I
+Landroid/R$styleable;->TextView_drawableLeft:I
+Landroid/R$styleable;->TextView_drawablePadding:I
+Landroid/R$styleable;->TextView_drawableRight:I
+Landroid/R$styleable;->TextView_drawableStart:I
+Landroid/R$styleable;->TextView_drawableTop:I
+Landroid/R$styleable;->TextView_editable:I
+Landroid/R$styleable;->TextView_ellipsize:I
+Landroid/R$styleable;->TextView_ems:I
+Landroid/R$styleable;->TextView_enabled:I
+Landroid/R$styleable;->TextView_freezesText:I
+Landroid/R$styleable;->TextView_gravity:I
+Landroid/R$styleable;->TextView_height:I
+Landroid/R$styleable;->TextView_hint:I
+Landroid/R$styleable;->TextView_imeActionId:I
+Landroid/R$styleable;->TextView_imeActionLabel:I
+Landroid/R$styleable;->TextView_imeOptions:I
+Landroid/R$styleable;->TextView_includeFontPadding:I
+Landroid/R$styleable;->TextView_inputMethod:I
+Landroid/R$styleable;->TextView_inputType:I
+Landroid/R$styleable;->TextView_lines:I
+Landroid/R$styleable;->TextView_lineSpacingExtra:I
+Landroid/R$styleable;->TextView_lineSpacingMultiplier:I
+Landroid/R$styleable;->TextView_linksClickable:I
+Landroid/R$styleable;->TextView_marqueeRepeatLimit:I
+Landroid/R$styleable;->TextView_maxEms:I
+Landroid/R$styleable;->TextView_maxHeight:I
+Landroid/R$styleable;->TextView_maxLength:I
+Landroid/R$styleable;->TextView_maxLines:I
+Landroid/R$styleable;->TextView_maxWidth:I
+Landroid/R$styleable;->TextView_minEms:I
+Landroid/R$styleable;->TextView_minHeight:I
+Landroid/R$styleable;->TextView_minLines:I
+Landroid/R$styleable;->TextView_minWidth:I
+Landroid/R$styleable;->TextView_numeric:I
+Landroid/R$styleable;->TextView_password:I
+Landroid/R$styleable;->TextView_phoneNumber:I
+Landroid/R$styleable;->TextView_privateImeOptions:I
+Landroid/R$styleable;->TextView_scrollHorizontally:I
+Landroid/R$styleable;->TextView_selectAllOnFocus:I
+Landroid/R$styleable;->TextView_shadowColor:I
+Landroid/R$styleable;->TextView_shadowDx:I
+Landroid/R$styleable;->TextView_shadowDy:I
+Landroid/R$styleable;->TextView_shadowRadius:I
+Landroid/R$styleable;->TextView_singleLine:I
+Landroid/R$styleable;->TextView_text:I
+Landroid/R$styleable;->TextView_textAllCaps:I
+Landroid/R$styleable;->TextView_textAppearance:I
+Landroid/R$styleable;->TextView_textColor:I
+Landroid/R$styleable;->TextView_textColorHighlight:I
+Landroid/R$styleable;->TextView_textColorHint:I
+Landroid/R$styleable;->TextView_textColorLink:I
+Landroid/R$styleable;->TextView_textCursorDrawable:I
+Landroid/R$styleable;->TextView_textIsSelectable:I
+Landroid/R$styleable;->TextView_textScaleX:I
+Landroid/R$styleable;->TextView_textSelectHandle:I
+Landroid/R$styleable;->TextView_textSelectHandleLeft:I
+Landroid/R$styleable;->TextView_textSelectHandleRight:I
+Landroid/R$styleable;->TextView_textSize:I
+Landroid/R$styleable;->TextView_textStyle:I
+Landroid/R$styleable;->TextView_typeface:I
+Landroid/R$styleable;->TextView_width:I
+Landroid/R$styleable;->Theme:[I
+Landroid/R$styleable;->View:[I
+Landroid/R$styleable;->ViewDrawableStates:[I
+Landroid/R$styleable;->ViewGroup_Layout:[I
+Landroid/R$styleable;->ViewGroup_Layout_layout_height:I
+Landroid/R$styleable;->ViewGroup_Layout_layout_width:I
+Landroid/R$styleable;->ViewGroup_MarginLayout:[I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_height:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_margin:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginBottom:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginLeft:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginRight:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginTop:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_width:I
+Landroid/R$styleable;->View_alpha:I
+Landroid/R$styleable;->View_background:I
+Landroid/R$styleable;->View_clickable:I
+Landroid/R$styleable;->View_contentDescription:I
+Landroid/R$styleable;->View_drawingCacheQuality:I
+Landroid/R$styleable;->View_duplicateParentState:I
+Landroid/R$styleable;->View_fadingEdge:I
+Landroid/R$styleable;->View_filterTouchesWhenObscured:I
+Landroid/R$styleable;->View_fitsSystemWindows:I
+Landroid/R$styleable;->View_focusable:I
+Landroid/R$styleable;->View_focusableInTouchMode:I
+Landroid/R$styleable;->View_hapticFeedbackEnabled:I
+Landroid/R$styleable;->View_id:I
+Landroid/R$styleable;->View_isScrollContainer:I
+Landroid/R$styleable;->View_keepScreenOn:I
+Landroid/R$styleable;->View_longClickable:I
+Landroid/R$styleable;->View_minHeight:I
+Landroid/R$styleable;->View_minWidth:I
+Landroid/R$styleable;->View_nextFocusDown:I
+Landroid/R$styleable;->View_nextFocusLeft:I
+Landroid/R$styleable;->View_nextFocusRight:I
+Landroid/R$styleable;->View_nextFocusUp:I
+Landroid/R$styleable;->View_onClick:I
+Landroid/R$styleable;->View_overScrollMode:I
+Landroid/R$styleable;->View_padding:I
+Landroid/R$styleable;->View_paddingBottom:I
+Landroid/R$styleable;->View_paddingEnd:I
+Landroid/R$styleable;->View_paddingLeft:I
+Landroid/R$styleable;->View_paddingRight:I
+Landroid/R$styleable;->View_paddingStart:I
+Landroid/R$styleable;->View_paddingTop:I
+Landroid/R$styleable;->View_rotation:I
+Landroid/R$styleable;->View_rotationX:I
+Landroid/R$styleable;->View_rotationY:I
+Landroid/R$styleable;->View_saveEnabled:I
+Landroid/R$styleable;->View_scaleX:I
+Landroid/R$styleable;->View_scaleY:I
+Landroid/R$styleable;->View_scrollbarDefaultDelayBeforeFade:I
+Landroid/R$styleable;->View_scrollbarFadeDuration:I
+Landroid/R$styleable;->View_scrollbars:I
+Landroid/R$styleable;->View_scrollbarSize:I
+Landroid/R$styleable;->View_scrollbarStyle:I
+Landroid/R$styleable;->View_scrollbarThumbHorizontal:I
+Landroid/R$styleable;->View_scrollbarThumbVertical:I
+Landroid/R$styleable;->View_scrollbarTrackHorizontal:I
+Landroid/R$styleable;->View_scrollbarTrackVertical:I
+Landroid/R$styleable;->View_scrollX:I
+Landroid/R$styleable;->View_scrollY:I
+Landroid/R$styleable;->View_soundEffectsEnabled:I
+Landroid/R$styleable;->View_tag:I
+Landroid/R$styleable;->View_transformPivotX:I
+Landroid/R$styleable;->View_transformPivotY:I
+Landroid/R$styleable;->View_translationX:I
+Landroid/R$styleable;->View_translationY:I
+Landroid/R$styleable;->View_visibility:I
+Landroid/R$styleable;->Window:[I
+Landroid/R$styleable;->Window_windowBackground:I
+Landroid/R$styleable;->Window_windowFrame:I
+Lcom/android/internal/R$anim;->fade_in:I
+Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
+Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
+Lcom/android/internal/R$array;->config_mobile_hotspot_provision_app:I
+Lcom/android/internal/R$array;->config_sms_enabled_locking_shift_tables:I
+Lcom/android/internal/R$array;->config_sms_enabled_single_shift_tables:I
+Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I
+Lcom/android/internal/R$array;->config_tether_upstream_types:I
+Lcom/android/internal/R$array;->config_tether_usb_regexs:I
+Lcom/android/internal/R$array;->config_tether_wifi_regexs:I
+Lcom/android/internal/R$array;->maps_starting_lat_lng:I
+Lcom/android/internal/R$array;->maps_starting_zoom:I
+Lcom/android/internal/R$attr;->actionBarStyle:I
+Lcom/android/internal/R$attr;->buttonStyle:I
+Lcom/android/internal/R$attr;->description:I
+Lcom/android/internal/R$attr;->editTextStyle:I
+Lcom/android/internal/R$attr;->mapViewStyle:I
+Lcom/android/internal/R$attr;->popupWindowStyle:I
+Lcom/android/internal/R$attr;->state_above_anchor:I
+Lcom/android/internal/R$attr;->state_focused:I
+Lcom/android/internal/R$attr;->state_pressed:I
+Lcom/android/internal/R$attr;->state_selected:I
+Lcom/android/internal/R$attr;->switchStyle:I
+Lcom/android/internal/R$attr;->text:I
+Lcom/android/internal/R$attr;->title:I
+Lcom/android/internal/R$attr;->webViewStyle:I
+Lcom/android/internal/R$bool;-><init>()V
+Lcom/android/internal/R$bool;->config_automatic_brightness_available:I
+Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I
+Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I
+Lcom/android/internal/R$bool;->config_showNavigationBar:I
+Lcom/android/internal/R$dimen;-><init>()V
+Lcom/android/internal/R$dimen;->item_touch_helper_max_drag_scroll_per_frame:I
+Lcom/android/internal/R$dimen;->navigation_bar_height:I
+Lcom/android/internal/R$dimen;->navigation_bar_height_landscape:I
+Lcom/android/internal/R$dimen;->navigation_bar_width:I
+Lcom/android/internal/R$dimen;->status_bar_height:I
+Lcom/android/internal/R$dimen;->toast_y_offset:I
+Lcom/android/internal/R$drawable;->btn_check_off:I
+Lcom/android/internal/R$drawable;->compass_arrow:I
+Lcom/android/internal/R$drawable;->compass_base:I
+Lcom/android/internal/R$drawable;->ic_maps_indicator_current_position_anim:I
+Lcom/android/internal/R$drawable;->ic_menu_close_clear_cancel:I
+Lcom/android/internal/R$drawable;->loading_tile_android:I
+Lcom/android/internal/R$drawable;->maps_google_logo:I
+Lcom/android/internal/R$drawable;->no_tile_256:I
+Lcom/android/internal/R$drawable;->reticle:I
+Lcom/android/internal/R$drawable;->stat_sys_download:I
+Lcom/android/internal/R$fraction;->config_autoBrightnessAdjustmentMaxGamma:I
+Lcom/android/internal/R$id;->account_name:I
+Lcom/android/internal/R$id;->account_type:I
+Lcom/android/internal/R$id;->alertTitle:I
+Lcom/android/internal/R$id;->allow_button:I
+Lcom/android/internal/R$id;->amPm:I
+Lcom/android/internal/R$id;->authtoken_type:I
+Lcom/android/internal/R$id;->background:I
+Lcom/android/internal/R$id;->back_button:I
+Lcom/android/internal/R$id;->body:I
+Lcom/android/internal/R$id;->buttonPanel:I
+Lcom/android/internal/R$id;->camera:I
+Lcom/android/internal/R$id;->cancel:I
+Lcom/android/internal/R$id;->clip_children_set_tag:I
+Lcom/android/internal/R$id;->clip_children_tag:I
+Lcom/android/internal/R$id;->clip_to_padding_tag:I
+Lcom/android/internal/R$id;->closeButton:I
+Lcom/android/internal/R$id;->content:I
+Lcom/android/internal/R$id;->contentPanel:I
+Lcom/android/internal/R$id;->custom:I
+Lcom/android/internal/R$id;->customPanel:I
+Lcom/android/internal/R$id;->datePicker:I
+Lcom/android/internal/R$id;->day:I
+Lcom/android/internal/R$id;->deny_button:I
+Lcom/android/internal/R$id;->description:I
+Lcom/android/internal/R$id;->edit:I
+Lcom/android/internal/R$id;->edittext_container:I
+Lcom/android/internal/R$id;->find_next:I
+Lcom/android/internal/R$id;->find_prev:I
+Lcom/android/internal/R$id;->icon:I
+Lcom/android/internal/R$id;->keyboard:I
+Lcom/android/internal/R$id;->keyboardView:I
+Lcom/android/internal/R$id;->line1:I
+Lcom/android/internal/R$id;->list_item:I
+Lcom/android/internal/R$id;->matches:I
+Lcom/android/internal/R$id;->mediacontroller_progress:I
+Lcom/android/internal/R$id;->media_actions:I
+Lcom/android/internal/R$id;->message:I
+Lcom/android/internal/R$id;->minute:I
+Lcom/android/internal/R$id;->month:I
+Lcom/android/internal/R$id;->name:I
+Lcom/android/internal/R$id;->notification_header:I
+Lcom/android/internal/R$id;->ok:I
+Lcom/android/internal/R$id;->overlay:I
+Lcom/android/internal/R$id;->packages_list:I
+Lcom/android/internal/R$id;->package_label:I
+Lcom/android/internal/R$id;->parentPanel:I
+Lcom/android/internal/R$id;->pause:I
+Lcom/android/internal/R$id;->pending_intent_tag:I
+Lcom/android/internal/R$id;->progress:I
+Lcom/android/internal/R$id;->redo:I
+Lcom/android/internal/R$id;->remote_input_tag:I
+Lcom/android/internal/R$id;->right_icon:I
+Lcom/android/internal/R$id;->search_src_text:I
+Lcom/android/internal/R$id;->share:I
+Lcom/android/internal/R$id;->shortcut:I
+Lcom/android/internal/R$id;->status_bar_latest_event_content:I
+Lcom/android/internal/R$id;->tabcontent:I
+Lcom/android/internal/R$id;->tabs:I
+Lcom/android/internal/R$id;->text1:I
+Lcom/android/internal/R$id;->text2:I
+Lcom/android/internal/R$id;->text:I
+Lcom/android/internal/R$id;->time:I
+Lcom/android/internal/R$id;->timePicker:I
+Lcom/android/internal/R$id;->time_current:I
+Lcom/android/internal/R$id;->title:I
+Lcom/android/internal/R$id;->titleDivider:I
+Lcom/android/internal/R$id;->titleDividerTop:I
+Lcom/android/internal/R$id;->title_container:I
+Lcom/android/internal/R$id;->title_template:I
+Lcom/android/internal/R$id;->topPanel:I
+Lcom/android/internal/R$id;->up:I
+Lcom/android/internal/R$id;->year:I
+Lcom/android/internal/R$id;->zoomControls:I
+Lcom/android/internal/R$id;->zoomMagnify:I
+Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
+Lcom/android/internal/R$integer;->config_screenBrightnessSettingMaximum:I
+Lcom/android/internal/R$integer;->config_screenBrightnessSettingMinimum:I
+Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
+Lcom/android/internal/R$interpolator;->accelerate_cubic:I
+Lcom/android/internal/R$interpolator;->decelerate_cubic:I
+Lcom/android/internal/R$layout;->notification_template_material_base:I
+Lcom/android/internal/R$layout;->preference_header_item:I
+Lcom/android/internal/R$layout;->screen_title:I
+Lcom/android/internal/R$layout;->select_dialog:I
+Lcom/android/internal/R$layout;->select_dialog_multichoice:I
+Lcom/android/internal/R$layout;->select_dialog_singlechoice:I
+Lcom/android/internal/R$layout;->webview_find:I
+Lcom/android/internal/R$layout;->zoom_magnify:I
+Lcom/android/internal/R$plurals;->matches_found:I
+Lcom/android/internal/R$raw;->loaderror:I
+Lcom/android/internal/R$raw;->nodomain:I
+Lcom/android/internal/R$string;->byteShort:I
+Lcom/android/internal/R$string;->cancel:I
+Lcom/android/internal/R$string;->enable_explore_by_touch_warning_title:I
+Lcom/android/internal/R$string;->gigabyteShort:I
+Lcom/android/internal/R$string;->kilobyteShort:I
+Lcom/android/internal/R$string;->map:I
+Lcom/android/internal/R$string;->megabyteShort:I
+Lcom/android/internal/R$string;->notification_title:I
+Lcom/android/internal/R$string;->no_matches:I
+Lcom/android/internal/R$string;->ok:I
+Lcom/android/internal/R$string;->petabyteShort:I
+Lcom/android/internal/R$string;->redo:I
+Lcom/android/internal/R$string;->share:I
+Lcom/android/internal/R$string;->terabyteShort:I
+Lcom/android/internal/R$string;->whichApplication:I
+Lcom/android/internal/R$style;->Animation_DropDownDown:I
+Lcom/android/internal/R$style;->Animation_DropDownUp:I
+Lcom/android/internal/R$style;->Animation_PopupWindow:I
+Lcom/android/internal/R$style;->Theme:I
+Lcom/android/internal/R$style;->Theme_Dialog_Alert:I
+Lcom/android/internal/R$style;->Theme_Holo_Light:I
+Lcom/android/internal/R$style;->Theme_Light:I
+Lcom/android/internal/R$styleable;-><init>()V
+Lcom/android/internal/R$styleable;->AbsListView:[I
+Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I
+Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I
+Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I
+Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I
+Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I
+Lcom/android/internal/R$styleable;->AbsListView_listSelector:I
+Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I
+Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I
+Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I
+Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I
+Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I
+Lcom/android/internal/R$styleable;->AbsSpinner:[I
+Lcom/android/internal/R$styleable;->AccountAuthenticator:[I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
+Lcom/android/internal/R$styleable;->ActionMode:[I
+Lcom/android/internal/R$styleable;->AdapterViewAnimator:[I
+Lcom/android/internal/R$styleable;->AdapterViewFlipper:[I
+Lcom/android/internal/R$styleable;->AlertDialog:[I
+Lcom/android/internal/R$styleable;->AnalogClock:[I
+Lcom/android/internal/R$styleable;->AndroidManifest:[I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_label:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_largeHeap:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I
+Lcom/android/internal/R$styleable;->AndroidManifestData:[I
+Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I
+Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I
+Lcom/android/internal/R$styleable;->AndroidManifestPackageVerifier:[I
+Lcom/android/internal/R$styleable;->AndroidManifestProvider:[I
+Lcom/android/internal/R$styleable;->AndroidManifestService:[I
+Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesLibrary:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_minSdkVersion:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_targetSdkVersion:I
+Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I
+Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I
+Lcom/android/internal/R$styleable;->AndroidManifest_versionCode:I
+Lcom/android/internal/R$styleable;->AndroidManifest_versionName:I
+Lcom/android/internal/R$styleable;->AutoCompleteTextView:[I
+Lcom/android/internal/R$styleable;->CheckBoxPreference:[I
+Lcom/android/internal/R$styleable;->CheckBoxPreference_disableDependentsState:I
+Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I
+Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I
+Lcom/android/internal/R$styleable;->CheckedTextView:[I
+Lcom/android/internal/R$styleable;->CheckedTextView_checked:I
+Lcom/android/internal/R$styleable;->CheckedTextView_checkMark:I
+Lcom/android/internal/R$styleable;->CompoundButton:[I
+Lcom/android/internal/R$styleable;->CompoundButton_button:I
+Lcom/android/internal/R$styleable;->CompoundButton_checked:I
+Lcom/android/internal/R$styleable;->ContactsDataKind:[I
+Lcom/android/internal/R$styleable;->DatePicker:[I
+Lcom/android/internal/R$styleable;->DialogPreference:[I
+Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I
+Lcom/android/internal/R$styleable;->Dream:[I
+Lcom/android/internal/R$styleable;->EdgeEffect:[I
+Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I
+Lcom/android/internal/R$styleable;->FastScroll:[I
+Lcom/android/internal/R$styleable;->FrameLayout:[I
+Lcom/android/internal/R$styleable;->FrameLayout_Layout:[I
+Lcom/android/internal/R$styleable;->Gallery:[I
+Lcom/android/internal/R$styleable;->GridView:[I
+Lcom/android/internal/R$styleable;->IconMenuView:[I
+Lcom/android/internal/R$styleable;->ImageView:[I
+Lcom/android/internal/R$styleable;->ImageView_scaleType:I
+Lcom/android/internal/R$styleable;->ImageView_src:I
+Lcom/android/internal/R$styleable;->Keyboard:[I
+Lcom/android/internal/R$styleable;->KeyboardView:[I
+Lcom/android/internal/R$styleable;->Keyboard_Key:[I
+Lcom/android/internal/R$styleable;->Keyboard_Row:[I
+Lcom/android/internal/R$styleable;->ListPreference:[I
+Lcom/android/internal/R$styleable;->ListPreference_entries:I
+Lcom/android/internal/R$styleable;->ListView:[I
+Lcom/android/internal/R$styleable;->ListView_divider:I
+Lcom/android/internal/R$styleable;->ListView_dividerHeight:I
+Lcom/android/internal/R$styleable;->ListView_entries:I
+Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I
+Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I
+Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I
+Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I
+Lcom/android/internal/R$styleable;->MapView:[I
+Lcom/android/internal/R$styleable;->MapView_apiKey:I
+Lcom/android/internal/R$styleable;->MenuGroup:[I
+Lcom/android/internal/R$styleable;->MenuItem:[I
+Lcom/android/internal/R$styleable;->NumberPicker:[I
+Lcom/android/internal/R$styleable;->PopupWindow:[I
+Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I
+Lcom/android/internal/R$styleable;->PopupWindow_popupBackground:I
+Lcom/android/internal/R$styleable;->Preference:[I
+Lcom/android/internal/R$styleable;->PreferenceGroup:[I
+Lcom/android/internal/R$styleable;->PreferenceGroup_orderingFromXml:I
+Lcom/android/internal/R$styleable;->Preference_defaultValue:I
+Lcom/android/internal/R$styleable;->Preference_dependency:I
+Lcom/android/internal/R$styleable;->Preference_enabled:I
+Lcom/android/internal/R$styleable;->Preference_fragment:I
+Lcom/android/internal/R$styleable;->Preference_icon:I
+Lcom/android/internal/R$styleable;->Preference_key:I
+Lcom/android/internal/R$styleable;->Preference_layout:I
+Lcom/android/internal/R$styleable;->Preference_order:I
+Lcom/android/internal/R$styleable;->Preference_persistent:I
+Lcom/android/internal/R$styleable;->Preference_selectable:I
+Lcom/android/internal/R$styleable;->Preference_shouldDisableView:I
+Lcom/android/internal/R$styleable;->Preference_summary:I
+Lcom/android/internal/R$styleable;->Preference_title:I
+Lcom/android/internal/R$styleable;->Preference_widgetLayout:I
+Lcom/android/internal/R$styleable;->ProgressBar:[I
+Lcom/android/internal/R$styleable;->QuickContactBadge:[I
+Lcom/android/internal/R$styleable;->RingtonePreference:[I
+Lcom/android/internal/R$styleable;->ScrollView:[I
+Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
+Lcom/android/internal/R$styleable;->SelectionModeDrawables:[I
+Lcom/android/internal/R$styleable;->Switch:[I
+Lcom/android/internal/R$styleable;->SwitchPreference:[I
+Lcom/android/internal/R$styleable;->SyncAdapter:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I
+Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I
+Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I
+Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I
+Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I
+Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
+Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
+Lcom/android/internal/R$styleable;->TabWidget:[I
+Lcom/android/internal/R$styleable;->TextAppearance:[I
+Lcom/android/internal/R$styleable;->TextAppearance_fontFamily:I
+Lcom/android/internal/R$styleable;->TextAppearance_textAllCaps:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColor:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColorHighlight:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColorHint:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColorLink:I
+Lcom/android/internal/R$styleable;->TextAppearance_textSize:I
+Lcom/android/internal/R$styleable;->TextAppearance_textStyle:I
+Lcom/android/internal/R$styleable;->TextAppearance_typeface:I
+Lcom/android/internal/R$styleable;->TextClock:[I
+Lcom/android/internal/R$styleable;->TextView:[I
+Lcom/android/internal/R$styleable;->TextViewAppearance:[I
+Lcom/android/internal/R$styleable;->TextViewAppearance_textAppearance:I
+Lcom/android/internal/R$styleable;->TextView_autoLink:I
+Lcom/android/internal/R$styleable;->TextView_autoText:I
+Lcom/android/internal/R$styleable;->TextView_bufferType:I
+Lcom/android/internal/R$styleable;->TextView_capitalize:I
+Lcom/android/internal/R$styleable;->TextView_cursorVisible:I
+Lcom/android/internal/R$styleable;->TextView_digits:I
+Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
+Lcom/android/internal/R$styleable;->TextView_drawableEnd:I
+Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
+Lcom/android/internal/R$styleable;->TextView_drawablePadding:I
+Lcom/android/internal/R$styleable;->TextView_drawableRight:I
+Lcom/android/internal/R$styleable;->TextView_drawableStart:I
+Lcom/android/internal/R$styleable;->TextView_drawableTop:I
+Lcom/android/internal/R$styleable;->TextView_editable:I
+Lcom/android/internal/R$styleable;->TextView_editorExtras:I
+Lcom/android/internal/R$styleable;->TextView_ellipsize:I
+Lcom/android/internal/R$styleable;->TextView_ems:I
+Lcom/android/internal/R$styleable;->TextView_enabled:I
+Lcom/android/internal/R$styleable;->TextView_freezesText:I
+Lcom/android/internal/R$styleable;->TextView_gravity:I
+Lcom/android/internal/R$styleable;->TextView_height:I
+Lcom/android/internal/R$styleable;->TextView_hint:I
+Lcom/android/internal/R$styleable;->TextView_imeActionId:I
+Lcom/android/internal/R$styleable;->TextView_imeActionLabel:I
+Lcom/android/internal/R$styleable;->TextView_imeOptions:I
+Lcom/android/internal/R$styleable;->TextView_includeFontPadding:I
+Lcom/android/internal/R$styleable;->TextView_inputMethod:I
+Lcom/android/internal/R$styleable;->TextView_inputType:I
+Lcom/android/internal/R$styleable;->TextView_lines:I
+Lcom/android/internal/R$styleable;->TextView_lineSpacingExtra:I
+Lcom/android/internal/R$styleable;->TextView_lineSpacingMultiplier:I
+Lcom/android/internal/R$styleable;->TextView_linksClickable:I
+Lcom/android/internal/R$styleable;->TextView_marqueeRepeatLimit:I
+Lcom/android/internal/R$styleable;->TextView_maxEms:I
+Lcom/android/internal/R$styleable;->TextView_maxHeight:I
+Lcom/android/internal/R$styleable;->TextView_maxLength:I
+Lcom/android/internal/R$styleable;->TextView_maxLines:I
+Lcom/android/internal/R$styleable;->TextView_maxWidth:I
+Lcom/android/internal/R$styleable;->TextView_minEms:I
+Lcom/android/internal/R$styleable;->TextView_minHeight:I
+Lcom/android/internal/R$styleable;->TextView_minLines:I
+Lcom/android/internal/R$styleable;->TextView_minWidth:I
+Lcom/android/internal/R$styleable;->TextView_numeric:I
+Lcom/android/internal/R$styleable;->TextView_password:I
+Lcom/android/internal/R$styleable;->TextView_phoneNumber:I
+Lcom/android/internal/R$styleable;->TextView_privateImeOptions:I
+Lcom/android/internal/R$styleable;->TextView_scrollHorizontally:I
+Lcom/android/internal/R$styleable;->TextView_selectAllOnFocus:I
+Lcom/android/internal/R$styleable;->TextView_shadowColor:I
+Lcom/android/internal/R$styleable;->TextView_shadowDx:I
+Lcom/android/internal/R$styleable;->TextView_shadowDy:I
+Lcom/android/internal/R$styleable;->TextView_shadowRadius:I
+Lcom/android/internal/R$styleable;->TextView_singleLine:I
+Lcom/android/internal/R$styleable;->TextView_text:I
+Lcom/android/internal/R$styleable;->TextView_textAllCaps:I
+Lcom/android/internal/R$styleable;->TextView_textAppearance:I
+Lcom/android/internal/R$styleable;->TextView_textColor:I
+Lcom/android/internal/R$styleable;->TextView_textColorHighlight:I
+Lcom/android/internal/R$styleable;->TextView_textColorHint:I
+Lcom/android/internal/R$styleable;->TextView_textColorLink:I
+Lcom/android/internal/R$styleable;->TextView_textCursorDrawable:I
+Lcom/android/internal/R$styleable;->TextView_textEditSuggestionItemLayout:I
+Lcom/android/internal/R$styleable;->TextView_textIsSelectable:I
+Lcom/android/internal/R$styleable;->TextView_textScaleX:I
+Lcom/android/internal/R$styleable;->TextView_textSelectHandle:I
+Lcom/android/internal/R$styleable;->TextView_textSelectHandleLeft:I
+Lcom/android/internal/R$styleable;->TextView_textSelectHandleRight:I
+Lcom/android/internal/R$styleable;->TextView_textSize:I
+Lcom/android/internal/R$styleable;->TextView_textStyle:I
+Lcom/android/internal/R$styleable;->TextView_typeface:I
+Lcom/android/internal/R$styleable;->TextView_width:I
+Lcom/android/internal/R$styleable;->Theme:[I
+Lcom/android/internal/R$styleable;->TwoLineListItem:[I
+Lcom/android/internal/R$styleable;->View:[I
+Lcom/android/internal/R$styleable;->ViewAnimator:[I
+Lcom/android/internal/R$styleable;->ViewFlipper:[I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_width:I
+Lcom/android/internal/R$styleable;->ViewStub:[I
+Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
+Lcom/android/internal/R$styleable;->ViewStub_layout:I
+Lcom/android/internal/R$styleable;->View_background:I
+Lcom/android/internal/R$styleable;->View_clickable:I
+Lcom/android/internal/R$styleable;->View_focusable:I
+Lcom/android/internal/R$styleable;->View_id:I
+Lcom/android/internal/R$styleable;->View_longClickable:I
+Lcom/android/internal/R$styleable;->WallpaperPreviewInfo:[I
+Lcom/android/internal/R$styleable;->Window:[I
+Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$styleable;->Window_windowBackground:I
+Lcom/android/internal/R$styleable;->Window_windowFullscreen:I
+Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
+Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
+Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
+Lcom/android/internal/R$xml;->power_profile:I
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 2d3394b..52caa42 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -238,270 +238,6 @@
Landroid/os/storage/IObbActionListener$Stub;-><init>()V
Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
-Landroid/R$styleable;->ActionBar:[I
-Landroid/R$styleable;->ActionBar_background:I
-Landroid/R$styleable;->ActionBar_backgroundSplit:I
-Landroid/R$styleable;->ActionBar_backgroundStacked:I
-Landroid/R$styleable;->ActionBar_divider:I
-Landroid/R$styleable;->ActionBar_itemPadding:I
-Landroid/R$styleable;->CalendarView:[I
-Landroid/R$styleable;->CalendarView_dateTextAppearance:I
-Landroid/R$styleable;->CalendarView_firstDayOfWeek:I
-Landroid/R$styleable;->CalendarView_focusedMonthDateColor:I
-Landroid/R$styleable;->CalendarView_selectedDateVerticalBar:I
-Landroid/R$styleable;->CalendarView_selectedWeekBackgroundColor:I
-Landroid/R$styleable;->CalendarView_shownWeekCount:I
-Landroid/R$styleable;->CalendarView_showWeekNumber:I
-Landroid/R$styleable;->CalendarView_unfocusedMonthDateColor:I
-Landroid/R$styleable;->CalendarView_weekDayTextAppearance:I
-Landroid/R$styleable;->CalendarView_weekNumberColor:I
-Landroid/R$styleable;->CalendarView_weekSeparatorLineColor:I
-Landroid/R$styleable;->CheckBoxPreference:[I
-Landroid/R$styleable;->CheckedTextView:[I
-Landroid/R$styleable;->CheckedTextView_checkMark:I
-Landroid/R$styleable;->CompoundButton:[I
-Landroid/R$styleable;->CompoundButton_button:I
-Landroid/R$styleable;->ContactsDataKind:[I
-Landroid/R$styleable;->DatePicker:[I
-Landroid/R$styleable;->DialogPreference:[I
-Landroid/R$styleable;->DrawableStates:[I
-Landroid/R$styleable;->ExpandableListView:[I
-Landroid/R$styleable;->FrameLayout_Layout:[I
-Landroid/R$styleable;->HorizontalScrollView:[I
-Landroid/R$styleable;->ImageView:[I
-Landroid/R$styleable;->ImageView_adjustViewBounds:I
-Landroid/R$styleable;->ImageView_baselineAlignBottom:I
-Landroid/R$styleable;->ImageView_cropToPadding:I
-Landroid/R$styleable;->ImageView_maxHeight:I
-Landroid/R$styleable;->ImageView_maxWidth:I
-Landroid/R$styleable;->ImageView_scaleType:I
-Landroid/R$styleable;->ImageView_src:I
-Landroid/R$styleable;->ImageView_tint:I
-Landroid/R$styleable;->Keyboard:[I
-Landroid/R$styleable;->Keyboard_horizontalGap:I
-Landroid/R$styleable;->Keyboard_Key:[I
-Landroid/R$styleable;->Keyboard_keyHeight:I
-Landroid/R$styleable;->Keyboard_keyWidth:I
-Landroid/R$styleable;->Keyboard_Key_codes:I
-Landroid/R$styleable;->Keyboard_Key_iconPreview:I
-Landroid/R$styleable;->Keyboard_Key_isModifier:I
-Landroid/R$styleable;->Keyboard_Key_isRepeatable:I
-Landroid/R$styleable;->Keyboard_Key_isSticky:I
-Landroid/R$styleable;->Keyboard_Key_keyEdgeFlags:I
-Landroid/R$styleable;->Keyboard_Key_keyIcon:I
-Landroid/R$styleable;->Keyboard_Key_keyLabel:I
-Landroid/R$styleable;->Keyboard_Key_keyOutputText:I
-Landroid/R$styleable;->Keyboard_Key_popupCharacters:I
-Landroid/R$styleable;->Keyboard_Key_popupKeyboard:I
-Landroid/R$styleable;->Keyboard_Row:[I
-Landroid/R$styleable;->Keyboard_Row_keyboardMode:I
-Landroid/R$styleable;->Keyboard_Row_rowEdgeFlags:I
-Landroid/R$styleable;->Keyboard_verticalGap:I
-Landroid/R$styleable;->LinearLayout:[I
-Landroid/R$styleable;->LinearLayout_baselineAligned:I
-Landroid/R$styleable;->LinearLayout_baselineAlignedChildIndex:I
-Landroid/R$styleable;->LinearLayout_divider:I
-Landroid/R$styleable;->LinearLayout_dividerPadding:I
-Landroid/R$styleable;->LinearLayout_gravity:I
-Landroid/R$styleable;->LinearLayout_Layout:[I
-Landroid/R$styleable;->LinearLayout_Layout_layout_gravity:I
-Landroid/R$styleable;->LinearLayout_Layout_layout_height:I
-Landroid/R$styleable;->LinearLayout_Layout_layout_weight:I
-Landroid/R$styleable;->LinearLayout_Layout_layout_width:I
-Landroid/R$styleable;->LinearLayout_measureWithLargestChild:I
-Landroid/R$styleable;->LinearLayout_orientation:I
-Landroid/R$styleable;->LinearLayout_showDividers:I
-Landroid/R$styleable;->ListView:[I
-Landroid/R$styleable;->ListView_divider:I
-Landroid/R$styleable;->ListView_dividerHeight:I
-Landroid/R$styleable;->LockPatternView:[I
-Landroid/R$styleable;->NumberPicker:[I
-Landroid/R$styleable;->NumberPicker_solidColor:I
-Landroid/R$styleable;->PopupWindow:[I
-Landroid/R$styleable;->ProgressBar:[I
-Landroid/R$styleable;->ProgressBar_indeterminateDrawable:I
-Landroid/R$styleable;->ProgressBar_indeterminateDuration:I
-Landroid/R$styleable;->ProgressBar_maxHeight:I
-Landroid/R$styleable;->ProgressBar_maxWidth:I
-Landroid/R$styleable;->ProgressBar_minHeight:I
-Landroid/R$styleable;->ProgressBar_minWidth:I
-Landroid/R$styleable;->ProgressBar_progressDrawable:I
-Landroid/R$styleable;->RingtonePreference:[I
-Landroid/R$styleable;->ScrollView:[I
-Landroid/R$styleable;->SearchView:[I
-Landroid/R$styleable;->SeekBar:[I
-Landroid/R$styleable;->SeekBar_thumb:I
-Landroid/R$styleable;->SeekBar_thumbOffset:I
-Landroid/R$styleable;->SlidingDrawer:[I
-Landroid/R$styleable;->SlidingDrawer_allowSingleTap:I
-Landroid/R$styleable;->SlidingDrawer_animateOnClick:I
-Landroid/R$styleable;->SlidingDrawer_bottomOffset:I
-Landroid/R$styleable;->SlidingDrawer_content:I
-Landroid/R$styleable;->SlidingDrawer_handle:I
-Landroid/R$styleable;->SlidingDrawer_orientation:I
-Landroid/R$styleable;->SlidingDrawer_topOffset:I
-Landroid/R$styleable;->Switch:[I
-Landroid/R$styleable;->Switch_showText:I
-Landroid/R$styleable;->Switch_splitTrack:I
-Landroid/R$styleable;->Switch_switchMinWidth:I
-Landroid/R$styleable;->Switch_switchPadding:I
-Landroid/R$styleable;->Switch_switchTextAppearance:I
-Landroid/R$styleable;->Switch_textOff:I
-Landroid/R$styleable;->Switch_textOn:I
-Landroid/R$styleable;->Switch_thumb:I
-Landroid/R$styleable;->Switch_thumbTextPadding:I
-Landroid/R$styleable;->Switch_track:I
-Landroid/R$styleable;->TextAppearance:[I
-Landroid/R$styleable;->TextAppearance_textAllCaps:I
-Landroid/R$styleable;->TextAppearance_textColor:I
-Landroid/R$styleable;->TextAppearance_textColorHighlight:I
-Landroid/R$styleable;->TextAppearance_textColorHint:I
-Landroid/R$styleable;->TextAppearance_textColorLink:I
-Landroid/R$styleable;->TextAppearance_textSize:I
-Landroid/R$styleable;->TextAppearance_textStyle:I
-Landroid/R$styleable;->TextAppearance_typeface:I
-Landroid/R$styleable;->TextView:[I
-Landroid/R$styleable;->TextView_autoLink:I
-Landroid/R$styleable;->TextView_autoText:I
-Landroid/R$styleable;->TextView_bufferType:I
-Landroid/R$styleable;->TextView_capitalize:I
-Landroid/R$styleable;->TextView_cursorVisible:I
-Landroid/R$styleable;->TextView_digits:I
-Landroid/R$styleable;->TextView_drawableBottom:I
-Landroid/R$styleable;->TextView_drawableEnd:I
-Landroid/R$styleable;->TextView_drawableLeft:I
-Landroid/R$styleable;->TextView_drawablePadding:I
-Landroid/R$styleable;->TextView_drawableRight:I
-Landroid/R$styleable;->TextView_drawableStart:I
-Landroid/R$styleable;->TextView_drawableTop:I
-Landroid/R$styleable;->TextView_editable:I
-Landroid/R$styleable;->TextView_ellipsize:I
-Landroid/R$styleable;->TextView_ems:I
-Landroid/R$styleable;->TextView_enabled:I
-Landroid/R$styleable;->TextView_freezesText:I
-Landroid/R$styleable;->TextView_gravity:I
-Landroid/R$styleable;->TextView_height:I
-Landroid/R$styleable;->TextView_hint:I
-Landroid/R$styleable;->TextView_imeActionId:I
-Landroid/R$styleable;->TextView_imeActionLabel:I
-Landroid/R$styleable;->TextView_imeOptions:I
-Landroid/R$styleable;->TextView_includeFontPadding:I
-Landroid/R$styleable;->TextView_inputMethod:I
-Landroid/R$styleable;->TextView_inputType:I
-Landroid/R$styleable;->TextView_lines:I
-Landroid/R$styleable;->TextView_lineSpacingExtra:I
-Landroid/R$styleable;->TextView_lineSpacingMultiplier:I
-Landroid/R$styleable;->TextView_linksClickable:I
-Landroid/R$styleable;->TextView_marqueeRepeatLimit:I
-Landroid/R$styleable;->TextView_maxEms:I
-Landroid/R$styleable;->TextView_maxHeight:I
-Landroid/R$styleable;->TextView_maxLength:I
-Landroid/R$styleable;->TextView_maxLines:I
-Landroid/R$styleable;->TextView_maxWidth:I
-Landroid/R$styleable;->TextView_minEms:I
-Landroid/R$styleable;->TextView_minHeight:I
-Landroid/R$styleable;->TextView_minLines:I
-Landroid/R$styleable;->TextView_minWidth:I
-Landroid/R$styleable;->TextView_numeric:I
-Landroid/R$styleable;->TextView_password:I
-Landroid/R$styleable;->TextView_phoneNumber:I
-Landroid/R$styleable;->TextView_privateImeOptions:I
-Landroid/R$styleable;->TextView_scrollHorizontally:I
-Landroid/R$styleable;->TextView_selectAllOnFocus:I
-Landroid/R$styleable;->TextView_shadowColor:I
-Landroid/R$styleable;->TextView_shadowDx:I
-Landroid/R$styleable;->TextView_shadowDy:I
-Landroid/R$styleable;->TextView_shadowRadius:I
-Landroid/R$styleable;->TextView_singleLine:I
-Landroid/R$styleable;->TextView_text:I
-Landroid/R$styleable;->TextView_textAllCaps:I
-Landroid/R$styleable;->TextView_textAppearance:I
-Landroid/R$styleable;->TextView_textColor:I
-Landroid/R$styleable;->TextView_textColorHighlight:I
-Landroid/R$styleable;->TextView_textColorHint:I
-Landroid/R$styleable;->TextView_textColorLink:I
-Landroid/R$styleable;->TextView_textCursorDrawable:I
-Landroid/R$styleable;->TextView_textIsSelectable:I
-Landroid/R$styleable;->TextView_textScaleX:I
-Landroid/R$styleable;->TextView_textSelectHandle:I
-Landroid/R$styleable;->TextView_textSelectHandleLeft:I
-Landroid/R$styleable;->TextView_textSelectHandleRight:I
-Landroid/R$styleable;->TextView_textSize:I
-Landroid/R$styleable;->TextView_textStyle:I
-Landroid/R$styleable;->TextView_typeface:I
-Landroid/R$styleable;->TextView_width:I
-Landroid/R$styleable;->Theme:[I
-Landroid/R$styleable;->View:[I
-Landroid/R$styleable;->ViewDrawableStates:[I
-Landroid/R$styleable;->ViewGroup_Layout:[I
-Landroid/R$styleable;->ViewGroup_Layout_layout_height:I
-Landroid/R$styleable;->ViewGroup_Layout_layout_width:I
-Landroid/R$styleable;->ViewGroup_MarginLayout:[I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_height:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_margin:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginBottom:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginLeft:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginRight:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginTop:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_width:I
-Landroid/R$styleable;->View_alpha:I
-Landroid/R$styleable;->View_background:I
-Landroid/R$styleable;->View_clickable:I
-Landroid/R$styleable;->View_contentDescription:I
-Landroid/R$styleable;->View_drawingCacheQuality:I
-Landroid/R$styleable;->View_duplicateParentState:I
-Landroid/R$styleable;->View_fadingEdge:I
-Landroid/R$styleable;->View_filterTouchesWhenObscured:I
-Landroid/R$styleable;->View_fitsSystemWindows:I
-Landroid/R$styleable;->View_focusable:I
-Landroid/R$styleable;->View_focusableInTouchMode:I
-Landroid/R$styleable;->View_hapticFeedbackEnabled:I
-Landroid/R$styleable;->View_id:I
-Landroid/R$styleable;->View_isScrollContainer:I
-Landroid/R$styleable;->View_keepScreenOn:I
-Landroid/R$styleable;->View_longClickable:I
-Landroid/R$styleable;->View_minHeight:I
-Landroid/R$styleable;->View_minWidth:I
-Landroid/R$styleable;->View_nextFocusDown:I
-Landroid/R$styleable;->View_nextFocusLeft:I
-Landroid/R$styleable;->View_nextFocusRight:I
-Landroid/R$styleable;->View_nextFocusUp:I
-Landroid/R$styleable;->View_onClick:I
-Landroid/R$styleable;->View_overScrollMode:I
-Landroid/R$styleable;->View_padding:I
-Landroid/R$styleable;->View_paddingBottom:I
-Landroid/R$styleable;->View_paddingEnd:I
-Landroid/R$styleable;->View_paddingLeft:I
-Landroid/R$styleable;->View_paddingRight:I
-Landroid/R$styleable;->View_paddingStart:I
-Landroid/R$styleable;->View_paddingTop:I
-Landroid/R$styleable;->View_rotation:I
-Landroid/R$styleable;->View_rotationX:I
-Landroid/R$styleable;->View_rotationY:I
-Landroid/R$styleable;->View_saveEnabled:I
-Landroid/R$styleable;->View_scaleX:I
-Landroid/R$styleable;->View_scaleY:I
-Landroid/R$styleable;->View_scrollbarDefaultDelayBeforeFade:I
-Landroid/R$styleable;->View_scrollbarFadeDuration:I
-Landroid/R$styleable;->View_scrollbars:I
-Landroid/R$styleable;->View_scrollbarSize:I
-Landroid/R$styleable;->View_scrollbarStyle:I
-Landroid/R$styleable;->View_scrollbarThumbHorizontal:I
-Landroid/R$styleable;->View_scrollbarThumbVertical:I
-Landroid/R$styleable;->View_scrollbarTrackHorizontal:I
-Landroid/R$styleable;->View_scrollbarTrackVertical:I
-Landroid/R$styleable;->View_scrollX:I
-Landroid/R$styleable;->View_scrollY:I
-Landroid/R$styleable;->View_soundEffectsEnabled:I
-Landroid/R$styleable;->View_tag:I
-Landroid/R$styleable;->View_transformPivotX:I
-Landroid/R$styleable;->View_transformPivotY:I
-Landroid/R$styleable;->View_translationX:I
-Landroid/R$styleable;->View_translationY:I
-Landroid/R$styleable;->View_visibility:I
-Landroid/R$styleable;->Window:[I
-Landroid/R$styleable;->Window_windowBackground:I
-Landroid/R$styleable;->Window_windowFrame:I
Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService;
Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
@@ -589,446 +325,6 @@
Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService;
Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback;
-Lcom/android/internal/R$anim;->fade_in:I
-Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
-Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
-Lcom/android/internal/R$array;->config_mobile_hotspot_provision_app:I
-Lcom/android/internal/R$array;->config_sms_enabled_locking_shift_tables:I
-Lcom/android/internal/R$array;->config_sms_enabled_single_shift_tables:I
-Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I
-Lcom/android/internal/R$array;->config_tether_upstream_types:I
-Lcom/android/internal/R$array;->config_tether_usb_regexs:I
-Lcom/android/internal/R$array;->config_tether_wifi_regexs:I
-Lcom/android/internal/R$array;->maps_starting_lat_lng:I
-Lcom/android/internal/R$array;->maps_starting_zoom:I
-Lcom/android/internal/R$attr;->actionBarStyle:I
-Lcom/android/internal/R$attr;->buttonStyle:I
-Lcom/android/internal/R$attr;->description:I
-Lcom/android/internal/R$attr;->editTextStyle:I
-Lcom/android/internal/R$attr;->mapViewStyle:I
-Lcom/android/internal/R$attr;->popupWindowStyle:I
-Lcom/android/internal/R$attr;->state_above_anchor:I
-Lcom/android/internal/R$attr;->state_focused:I
-Lcom/android/internal/R$attr;->state_pressed:I
-Lcom/android/internal/R$attr;->state_selected:I
-Lcom/android/internal/R$attr;->switchStyle:I
-Lcom/android/internal/R$attr;->text:I
-Lcom/android/internal/R$attr;->title:I
-Lcom/android/internal/R$attr;->webViewStyle:I
-Lcom/android/internal/R$bool;-><init>()V
-Lcom/android/internal/R$bool;->config_automatic_brightness_available:I
-Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I
-Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I
-Lcom/android/internal/R$bool;->config_showNavigationBar:I
-Lcom/android/internal/R$dimen;-><init>()V
-Lcom/android/internal/R$dimen;->item_touch_helper_max_drag_scroll_per_frame:I
-Lcom/android/internal/R$dimen;->navigation_bar_height:I
-Lcom/android/internal/R$dimen;->navigation_bar_height_landscape:I
-Lcom/android/internal/R$dimen;->navigation_bar_width:I
-Lcom/android/internal/R$dimen;->status_bar_height:I
-Lcom/android/internal/R$dimen;->toast_y_offset:I
-Lcom/android/internal/R$drawable;->btn_check_off:I
-Lcom/android/internal/R$drawable;->compass_arrow:I
-Lcom/android/internal/R$drawable;->compass_base:I
-Lcom/android/internal/R$drawable;->ic_maps_indicator_current_position_anim:I
-Lcom/android/internal/R$drawable;->ic_menu_close_clear_cancel:I
-Lcom/android/internal/R$drawable;->loading_tile_android:I
-Lcom/android/internal/R$drawable;->maps_google_logo:I
-Lcom/android/internal/R$drawable;->no_tile_256:I
-Lcom/android/internal/R$drawable;->reticle:I
-Lcom/android/internal/R$drawable;->stat_sys_download:I
-Lcom/android/internal/R$fraction;->config_autoBrightnessAdjustmentMaxGamma:I
-Lcom/android/internal/R$id;->account_name:I
-Lcom/android/internal/R$id;->account_type:I
-Lcom/android/internal/R$id;->alertTitle:I
-Lcom/android/internal/R$id;->allow_button:I
-Lcom/android/internal/R$id;->amPm:I
-Lcom/android/internal/R$id;->authtoken_type:I
-Lcom/android/internal/R$id;->background:I
-Lcom/android/internal/R$id;->back_button:I
-Lcom/android/internal/R$id;->body:I
-Lcom/android/internal/R$id;->buttonPanel:I
-Lcom/android/internal/R$id;->camera:I
-Lcom/android/internal/R$id;->cancel:I
-Lcom/android/internal/R$id;->clip_children_set_tag:I
-Lcom/android/internal/R$id;->clip_children_tag:I
-Lcom/android/internal/R$id;->clip_to_padding_tag:I
-Lcom/android/internal/R$id;->closeButton:I
-Lcom/android/internal/R$id;->content:I
-Lcom/android/internal/R$id;->contentPanel:I
-Lcom/android/internal/R$id;->custom:I
-Lcom/android/internal/R$id;->customPanel:I
-Lcom/android/internal/R$id;->datePicker:I
-Lcom/android/internal/R$id;->day:I
-Lcom/android/internal/R$id;->deny_button:I
-Lcom/android/internal/R$id;->description:I
-Lcom/android/internal/R$id;->edit:I
-Lcom/android/internal/R$id;->edittext_container:I
-Lcom/android/internal/R$id;->find_next:I
-Lcom/android/internal/R$id;->find_prev:I
-Lcom/android/internal/R$id;->icon:I
-Lcom/android/internal/R$id;->keyboard:I
-Lcom/android/internal/R$id;->keyboardView:I
-Lcom/android/internal/R$id;->line1:I
-Lcom/android/internal/R$id;->list_item:I
-Lcom/android/internal/R$id;->matches:I
-Lcom/android/internal/R$id;->mediacontroller_progress:I
-Lcom/android/internal/R$id;->media_actions:I
-Lcom/android/internal/R$id;->message:I
-Lcom/android/internal/R$id;->minute:I
-Lcom/android/internal/R$id;->month:I
-Lcom/android/internal/R$id;->name:I
-Lcom/android/internal/R$id;->notification_header:I
-Lcom/android/internal/R$id;->ok:I
-Lcom/android/internal/R$id;->overlay:I
-Lcom/android/internal/R$id;->packages_list:I
-Lcom/android/internal/R$id;->package_label:I
-Lcom/android/internal/R$id;->parentPanel:I
-Lcom/android/internal/R$id;->pause:I
-Lcom/android/internal/R$id;->pending_intent_tag:I
-Lcom/android/internal/R$id;->progress:I
-Lcom/android/internal/R$id;->redo:I
-Lcom/android/internal/R$id;->remote_input_tag:I
-Lcom/android/internal/R$id;->right_icon:I
-Lcom/android/internal/R$id;->search_src_text:I
-Lcom/android/internal/R$id;->share:I
-Lcom/android/internal/R$id;->shortcut:I
-Lcom/android/internal/R$id;->status_bar_latest_event_content:I
-Lcom/android/internal/R$id;->tabcontent:I
-Lcom/android/internal/R$id;->tabs:I
-Lcom/android/internal/R$id;->text1:I
-Lcom/android/internal/R$id;->text2:I
-Lcom/android/internal/R$id;->text:I
-Lcom/android/internal/R$id;->time:I
-Lcom/android/internal/R$id;->timePicker:I
-Lcom/android/internal/R$id;->time_current:I
-Lcom/android/internal/R$id;->title:I
-Lcom/android/internal/R$id;->titleDivider:I
-Lcom/android/internal/R$id;->titleDividerTop:I
-Lcom/android/internal/R$id;->title_container:I
-Lcom/android/internal/R$id;->title_template:I
-Lcom/android/internal/R$id;->topPanel:I
-Lcom/android/internal/R$id;->up:I
-Lcom/android/internal/R$id;->year:I
-Lcom/android/internal/R$id;->zoomControls:I
-Lcom/android/internal/R$id;->zoomMagnify:I
-Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
-Lcom/android/internal/R$integer;->config_screenBrightnessSettingMaximum:I
-Lcom/android/internal/R$integer;->config_screenBrightnessSettingMinimum:I
-Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
-Lcom/android/internal/R$interpolator;->accelerate_cubic:I
-Lcom/android/internal/R$interpolator;->decelerate_cubic:I
-Lcom/android/internal/R$layout;->notification_template_material_base:I
-Lcom/android/internal/R$layout;->preference_header_item:I
-Lcom/android/internal/R$layout;->screen_title:I
-Lcom/android/internal/R$layout;->select_dialog:I
-Lcom/android/internal/R$layout;->select_dialog_multichoice:I
-Lcom/android/internal/R$layout;->select_dialog_singlechoice:I
-Lcom/android/internal/R$layout;->webview_find:I
-Lcom/android/internal/R$layout;->zoom_magnify:I
-Lcom/android/internal/R$plurals;->matches_found:I
-Lcom/android/internal/R$raw;->loaderror:I
-Lcom/android/internal/R$raw;->nodomain:I
-Lcom/android/internal/R$string;->byteShort:I
-Lcom/android/internal/R$string;->cancel:I
-Lcom/android/internal/R$string;->enable_explore_by_touch_warning_title:I
-Lcom/android/internal/R$string;->gigabyteShort:I
-Lcom/android/internal/R$string;->kilobyteShort:I
-Lcom/android/internal/R$string;->map:I
-Lcom/android/internal/R$string;->megabyteShort:I
-Lcom/android/internal/R$string;->notification_title:I
-Lcom/android/internal/R$string;->no_matches:I
-Lcom/android/internal/R$string;->ok:I
-Lcom/android/internal/R$string;->petabyteShort:I
-Lcom/android/internal/R$string;->redo:I
-Lcom/android/internal/R$string;->share:I
-Lcom/android/internal/R$string;->terabyteShort:I
-Lcom/android/internal/R$string;->whichApplication:I
-Lcom/android/internal/R$style;->Animation_DropDownDown:I
-Lcom/android/internal/R$style;->Animation_DropDownUp:I
-Lcom/android/internal/R$style;->Animation_PopupWindow:I
-Lcom/android/internal/R$style;->Theme:I
-Lcom/android/internal/R$style;->Theme_Dialog_Alert:I
-Lcom/android/internal/R$style;->Theme_Holo_Light:I
-Lcom/android/internal/R$style;->Theme_Light:I
-Lcom/android/internal/R$styleable;-><init>()V
-Lcom/android/internal/R$styleable;->AbsListView:[I
-Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I
-Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I
-Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I
-Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I
-Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I
-Lcom/android/internal/R$styleable;->AbsListView_listSelector:I
-Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I
-Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I
-Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I
-Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I
-Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I
-Lcom/android/internal/R$styleable;->AbsSpinner:[I
-Lcom/android/internal/R$styleable;->AccountAuthenticator:[I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
-Lcom/android/internal/R$styleable;->ActionMode:[I
-Lcom/android/internal/R$styleable;->AdapterViewAnimator:[I
-Lcom/android/internal/R$styleable;->AdapterViewFlipper:[I
-Lcom/android/internal/R$styleable;->AlertDialog:[I
-Lcom/android/internal/R$styleable;->AnalogClock:[I
-Lcom/android/internal/R$styleable;->AndroidManifest:[I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_label:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_largeHeap:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_permission:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I
-Lcom/android/internal/R$styleable;->AndroidManifestData:[I
-Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I
-Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I
-Lcom/android/internal/R$styleable;->AndroidManifestPackageVerifier:[I
-Lcom/android/internal/R$styleable;->AndroidManifestProvider:[I
-Lcom/android/internal/R$styleable;->AndroidManifestService:[I
-Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_process:I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesLibrary:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_minSdkVersion:I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_targetSdkVersion:I
-Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I
-Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I
-Lcom/android/internal/R$styleable;->AndroidManifest_versionCode:I
-Lcom/android/internal/R$styleable;->AndroidManifest_versionName:I
-Lcom/android/internal/R$styleable;->AutoCompleteTextView:[I
-Lcom/android/internal/R$styleable;->CheckBoxPreference:[I
-Lcom/android/internal/R$styleable;->CheckBoxPreference_disableDependentsState:I
-Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I
-Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I
-Lcom/android/internal/R$styleable;->CheckedTextView:[I
-Lcom/android/internal/R$styleable;->CheckedTextView_checked:I
-Lcom/android/internal/R$styleable;->CheckedTextView_checkMark:I
-Lcom/android/internal/R$styleable;->CompoundButton:[I
-Lcom/android/internal/R$styleable;->CompoundButton_button:I
-Lcom/android/internal/R$styleable;->CompoundButton_checked:I
-Lcom/android/internal/R$styleable;->ContactsDataKind:[I
-Lcom/android/internal/R$styleable;->DatePicker:[I
-Lcom/android/internal/R$styleable;->DialogPreference:[I
-Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I
-Lcom/android/internal/R$styleable;->Dream:[I
-Lcom/android/internal/R$styleable;->EdgeEffect:[I
-Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I
-Lcom/android/internal/R$styleable;->FastScroll:[I
-Lcom/android/internal/R$styleable;->FrameLayout:[I
-Lcom/android/internal/R$styleable;->FrameLayout_Layout:[I
-Lcom/android/internal/R$styleable;->Gallery:[I
-Lcom/android/internal/R$styleable;->GridView:[I
-Lcom/android/internal/R$styleable;->IconMenuView:[I
-Lcom/android/internal/R$styleable;->ImageView:[I
-Lcom/android/internal/R$styleable;->ImageView_scaleType:I
-Lcom/android/internal/R$styleable;->ImageView_src:I
-Lcom/android/internal/R$styleable;->Keyboard:[I
-Lcom/android/internal/R$styleable;->KeyboardView:[I
-Lcom/android/internal/R$styleable;->Keyboard_Key:[I
-Lcom/android/internal/R$styleable;->Keyboard_Row:[I
-Lcom/android/internal/R$styleable;->ListPreference:[I
-Lcom/android/internal/R$styleable;->ListPreference_entries:I
-Lcom/android/internal/R$styleable;->ListView:[I
-Lcom/android/internal/R$styleable;->ListView_divider:I
-Lcom/android/internal/R$styleable;->ListView_dividerHeight:I
-Lcom/android/internal/R$styleable;->ListView_entries:I
-Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I
-Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I
-Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I
-Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I
-Lcom/android/internal/R$styleable;->MapView:[I
-Lcom/android/internal/R$styleable;->MapView_apiKey:I
-Lcom/android/internal/R$styleable;->MenuGroup:[I
-Lcom/android/internal/R$styleable;->MenuItem:[I
-Lcom/android/internal/R$styleable;->NumberPicker:[I
-Lcom/android/internal/R$styleable;->PopupWindow:[I
-Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I
-Lcom/android/internal/R$styleable;->PopupWindow_popupBackground:I
-Lcom/android/internal/R$styleable;->Preference:[I
-Lcom/android/internal/R$styleable;->PreferenceGroup:[I
-Lcom/android/internal/R$styleable;->PreferenceGroup_orderingFromXml:I
-Lcom/android/internal/R$styleable;->Preference_defaultValue:I
-Lcom/android/internal/R$styleable;->Preference_dependency:I
-Lcom/android/internal/R$styleable;->Preference_enabled:I
-Lcom/android/internal/R$styleable;->Preference_fragment:I
-Lcom/android/internal/R$styleable;->Preference_icon:I
-Lcom/android/internal/R$styleable;->Preference_key:I
-Lcom/android/internal/R$styleable;->Preference_layout:I
-Lcom/android/internal/R$styleable;->Preference_order:I
-Lcom/android/internal/R$styleable;->Preference_persistent:I
-Lcom/android/internal/R$styleable;->Preference_selectable:I
-Lcom/android/internal/R$styleable;->Preference_shouldDisableView:I
-Lcom/android/internal/R$styleable;->Preference_summary:I
-Lcom/android/internal/R$styleable;->Preference_title:I
-Lcom/android/internal/R$styleable;->Preference_widgetLayout:I
-Lcom/android/internal/R$styleable;->ProgressBar:[I
-Lcom/android/internal/R$styleable;->QuickContactBadge:[I
-Lcom/android/internal/R$styleable;->RingtonePreference:[I
-Lcom/android/internal/R$styleable;->ScrollView:[I
-Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
-Lcom/android/internal/R$styleable;->SelectionModeDrawables:[I
-Lcom/android/internal/R$styleable;->Switch:[I
-Lcom/android/internal/R$styleable;->SwitchPreference:[I
-Lcom/android/internal/R$styleable;->SyncAdapter:[I
-Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I
-Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I
-Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I
-Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I
-Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I
-Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
-Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
-Lcom/android/internal/R$styleable;->TabWidget:[I
-Lcom/android/internal/R$styleable;->TextAppearance:[I
-Lcom/android/internal/R$styleable;->TextAppearance_fontFamily:I
-Lcom/android/internal/R$styleable;->TextAppearance_textAllCaps:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColor:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColorHighlight:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColorHint:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColorLink:I
-Lcom/android/internal/R$styleable;->TextAppearance_textSize:I
-Lcom/android/internal/R$styleable;->TextAppearance_textStyle:I
-Lcom/android/internal/R$styleable;->TextAppearance_typeface:I
-Lcom/android/internal/R$styleable;->TextClock:[I
-Lcom/android/internal/R$styleable;->TextView:[I
-Lcom/android/internal/R$styleable;->TextViewAppearance:[I
-Lcom/android/internal/R$styleable;->TextViewAppearance_textAppearance:I
-Lcom/android/internal/R$styleable;->TextView_autoLink:I
-Lcom/android/internal/R$styleable;->TextView_autoText:I
-Lcom/android/internal/R$styleable;->TextView_bufferType:I
-Lcom/android/internal/R$styleable;->TextView_capitalize:I
-Lcom/android/internal/R$styleable;->TextView_cursorVisible:I
-Lcom/android/internal/R$styleable;->TextView_digits:I
-Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
-Lcom/android/internal/R$styleable;->TextView_drawableEnd:I
-Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
-Lcom/android/internal/R$styleable;->TextView_drawablePadding:I
-Lcom/android/internal/R$styleable;->TextView_drawableRight:I
-Lcom/android/internal/R$styleable;->TextView_drawableStart:I
-Lcom/android/internal/R$styleable;->TextView_drawableTop:I
-Lcom/android/internal/R$styleable;->TextView_editable:I
-Lcom/android/internal/R$styleable;->TextView_editorExtras:I
-Lcom/android/internal/R$styleable;->TextView_ellipsize:I
-Lcom/android/internal/R$styleable;->TextView_ems:I
-Lcom/android/internal/R$styleable;->TextView_enabled:I
-Lcom/android/internal/R$styleable;->TextView_freezesText:I
-Lcom/android/internal/R$styleable;->TextView_gravity:I
-Lcom/android/internal/R$styleable;->TextView_height:I
-Lcom/android/internal/R$styleable;->TextView_hint:I
-Lcom/android/internal/R$styleable;->TextView_imeActionId:I
-Lcom/android/internal/R$styleable;->TextView_imeActionLabel:I
-Lcom/android/internal/R$styleable;->TextView_imeOptions:I
-Lcom/android/internal/R$styleable;->TextView_includeFontPadding:I
-Lcom/android/internal/R$styleable;->TextView_inputMethod:I
-Lcom/android/internal/R$styleable;->TextView_inputType:I
-Lcom/android/internal/R$styleable;->TextView_lines:I
-Lcom/android/internal/R$styleable;->TextView_lineSpacingExtra:I
-Lcom/android/internal/R$styleable;->TextView_lineSpacingMultiplier:I
-Lcom/android/internal/R$styleable;->TextView_linksClickable:I
-Lcom/android/internal/R$styleable;->TextView_marqueeRepeatLimit:I
-Lcom/android/internal/R$styleable;->TextView_maxEms:I
-Lcom/android/internal/R$styleable;->TextView_maxHeight:I
-Lcom/android/internal/R$styleable;->TextView_maxLength:I
-Lcom/android/internal/R$styleable;->TextView_maxLines:I
-Lcom/android/internal/R$styleable;->TextView_maxWidth:I
-Lcom/android/internal/R$styleable;->TextView_minEms:I
-Lcom/android/internal/R$styleable;->TextView_minHeight:I
-Lcom/android/internal/R$styleable;->TextView_minLines:I
-Lcom/android/internal/R$styleable;->TextView_minWidth:I
-Lcom/android/internal/R$styleable;->TextView_numeric:I
-Lcom/android/internal/R$styleable;->TextView_password:I
-Lcom/android/internal/R$styleable;->TextView_phoneNumber:I
-Lcom/android/internal/R$styleable;->TextView_privateImeOptions:I
-Lcom/android/internal/R$styleable;->TextView_scrollHorizontally:I
-Lcom/android/internal/R$styleable;->TextView_selectAllOnFocus:I
-Lcom/android/internal/R$styleable;->TextView_shadowColor:I
-Lcom/android/internal/R$styleable;->TextView_shadowDx:I
-Lcom/android/internal/R$styleable;->TextView_shadowDy:I
-Lcom/android/internal/R$styleable;->TextView_shadowRadius:I
-Lcom/android/internal/R$styleable;->TextView_singleLine:I
-Lcom/android/internal/R$styleable;->TextView_text:I
-Lcom/android/internal/R$styleable;->TextView_textAllCaps:I
-Lcom/android/internal/R$styleable;->TextView_textAppearance:I
-Lcom/android/internal/R$styleable;->TextView_textColor:I
-Lcom/android/internal/R$styleable;->TextView_textColorHighlight:I
-Lcom/android/internal/R$styleable;->TextView_textColorHint:I
-Lcom/android/internal/R$styleable;->TextView_textColorLink:I
-Lcom/android/internal/R$styleable;->TextView_textCursorDrawable:I
-Lcom/android/internal/R$styleable;->TextView_textEditSuggestionItemLayout:I
-Lcom/android/internal/R$styleable;->TextView_textIsSelectable:I
-Lcom/android/internal/R$styleable;->TextView_textScaleX:I
-Lcom/android/internal/R$styleable;->TextView_textSelectHandle:I
-Lcom/android/internal/R$styleable;->TextView_textSelectHandleLeft:I
-Lcom/android/internal/R$styleable;->TextView_textSelectHandleRight:I
-Lcom/android/internal/R$styleable;->TextView_textSize:I
-Lcom/android/internal/R$styleable;->TextView_textStyle:I
-Lcom/android/internal/R$styleable;->TextView_typeface:I
-Lcom/android/internal/R$styleable;->TextView_width:I
-Lcom/android/internal/R$styleable;->Theme:[I
-Lcom/android/internal/R$styleable;->TwoLineListItem:[I
-Lcom/android/internal/R$styleable;->View:[I
-Lcom/android/internal/R$styleable;->ViewAnimator:[I
-Lcom/android/internal/R$styleable;->ViewFlipper:[I
-Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I
-Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I
-Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_width:I
-Lcom/android/internal/R$styleable;->ViewStub:[I
-Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
-Lcom/android/internal/R$styleable;->ViewStub_layout:I
-Lcom/android/internal/R$styleable;->View_background:I
-Lcom/android/internal/R$styleable;->View_clickable:I
-Lcom/android/internal/R$styleable;->View_focusable:I
-Lcom/android/internal/R$styleable;->View_id:I
-Lcom/android/internal/R$styleable;->View_longClickable:I
-Lcom/android/internal/R$styleable;->WallpaperPreviewInfo:[I
-Lcom/android/internal/R$styleable;->Window:[I
-Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
-Lcom/android/internal/R$styleable;->Window_windowBackground:I
-Lcom/android/internal/R$styleable;->Window_windowFullscreen:I
-Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
-Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
-Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
-Lcom/android/internal/R$xml;->power_profile:I
Lcom/android/internal/statusbar/IStatusBar$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBar;
Lcom/android/internal/statusbar/IStatusBarService$Stub;-><init>()V
Lcom/android/internal/statusbar/IStatusBarService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBarService;
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 25cd342..6470a04 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -103,8 +103,6 @@
* When writing an activity to satisfy these requests one must pass in the AccountManagerResponse
* and return the result via that response when the activity finishes (or whenever else the
* activity author deems it is the correct time to respond).
- * The {@link AccountAuthenticatorActivity} handles this, so one may wish to extend that when
- * writing activities to handle these requests.
*/
public abstract class AbstractAccountAuthenticator {
private static final String TAG = "AccountAuthenticator";
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
index 967aa04..65ba35f 100644
--- a/core/java/android/accounts/AccountAuthenticatorActivity.java
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -32,7 +32,11 @@
* This result will be sent as the result of the request when the activity finishes. If this
* is never set or if it is set to null then error {@link AccountManager#ERROR_CODE_CANCELED}
* will be called on the response.
+ *
+ * @deprecated Applications should extend Activity themselves. This class is not compatible with
+ * AppCompat, and the functionality it provides is not complex.
*/
+@Deprecated
public class AccountAuthenticatorActivity extends Activity {
private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
private Bundle mResultBundle = null;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9902f6a..794ffcb 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2224,6 +2224,15 @@
}
@Override
+ public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
+ try {
+ return createPackageContextAsUser(getPackageName(), flags, user);
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException("Own package not found: package=" + getPackageName());
+ }
+ }
+
+ @Override
public Context createContextForSplit(String splitName) throws NameNotFoundException {
if (!mPackageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
// All Splits are always loaded.
diff --git a/core/java/android/app/ExpandableListActivity.java b/core/java/android/app/ExpandableListActivity.java
index e08f25a..22de878 100644
--- a/core/java/android/app/ExpandableListActivity.java
+++ b/core/java/android/app/ExpandableListActivity.java
@@ -150,7 +150,11 @@
*
* @see #setListAdapter
* @see android.widget.ExpandableListView
+ *
+ * @deprecated Use {@link androidx.recyclerview.widget.RecyclerView} or use
+ * {@link android.widget.ExpandableListView} directly
*/
+@Deprecated
public class ExpandableListActivity extends Activity implements
OnCreateContextMenuListener,
ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index f2c9f61..a3e0845 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -25,7 +25,7 @@
* Enables the car mode. Only the system can do this.
* @hide
*/
- void enableCarMode(int flags);
+ void enableCarMode(int flags, int priority, String callingPackage);
/**
* Disables the car mode.
@@ -34,6 +34,12 @@
void disableCarMode(int flags);
/**
+ * Disables car mode (the original version is marked unsupported app usage so cannot be changed
+ * for the time being).
+ */
+ void disableCarModeByCallingPackage(int flags, String callingPackage);
+
+ /**
* Return the current running mode.
*/
int getCurrentModeType();
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 88e2356..b495b3c 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -53,7 +53,11 @@
* Displays a list of all activities which can be performed
* for a given intent. Launches when clicked.
*
+ * @deprecated Applications can implement this UI themselves using
+ * {@link androidx.recyclerview.widget.RecyclerView} and
+ * {@link android.content.pm.PackageManager#queryIntentActivities(Intent, int)}
*/
+@Deprecated
public abstract class LauncherActivity extends ListActivity {
Intent mIntent;
PackageManager mPackageManager;
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 2162521..810cca2 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -171,7 +171,11 @@
*
* @see #setListAdapter
* @see android.widget.ListView
+ *
+ * @deprecated Use {@link androidx.fragment.app.ListFragment} or
+ * {@link androidx.recyclerview.widget.RecyclerView} to implement your Activity instead.
*/
+@Deprecated
public class ListActivity extends Activity {
/**
* This field should be made private, so it is hidden from the SDK.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ceadd85..47f0cf8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -628,6 +628,13 @@
*/
public static final int FLAG_BUBBLE = 0x00001000;
+ /** @hide */
+ @IntDef({FLAG_SHOW_LIGHTS, FLAG_ONGOING_EVENT, FLAG_INSISTENT, FLAG_ONLY_ALERT_ONCE,
+ FLAG_AUTO_CANCEL, FLAG_NO_CLEAR, FLAG_FOREGROUND_SERVICE, FLAG_HIGH_PRIORITY,
+ FLAG_LOCAL_ONLY, FLAG_GROUP_SUMMARY, FLAG_AUTOGROUP_SUMMARY, FLAG_BUBBLE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NotificationFlags{};
+
public int flags;
/** @hide */
@@ -4537,10 +4544,15 @@
}
/**
- * @hide
+ * Set the value for a notification flag
+ *
+ * @param mask Bit mask of the flag
+ * @param value Status (on/off) of the flag
+ *
+ * @return The same Builder.
*/
@NonNull
- public Builder setFlag(int mask, boolean value) {
+ public Builder setFlag(@NotificationFlags int mask, boolean value) {
if (value) {
mN.flags |= mask;
} else {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 587d7b1..29cb3c1 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -653,7 +653,7 @@
new CachedServiceFetcher<UiModeManager>() {
@Override
public UiModeManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- return new UiModeManager();
+ return new UiModeManager(ctx.getOuterContext());
}});
registerService(Context.USB_SERVICE, UsbManager.class,
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 46316e1..8324787 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -17,6 +17,10 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -68,6 +72,25 @@
* of the broadcast to {@link Activity#RESULT_CANCELED}.
*/
public static String ACTION_ENTER_CAR_MODE = "android.app.action.ENTER_CAR_MODE";
+
+ /**
+ * Broadcast sent when the device's UI has switched to car mode, either by being placed in a car
+ * dock or explicit action of the user.
+ * <p>
+ * In addition to the behavior for {@link #ACTION_ENTER_CAR_MODE}, this broadcast includes the
+ * package name of the app which requested to enter car mode in the
+ * {@link #EXTRA_CALLING_PACKAGE}. If an app requested to enter car mode using
+ * {@link #enableCarMode(int, int)} and specified a priority this will be specified in the
+ * {@link #EXTRA_PRIORITY}.
+ *
+ * This is primarily intended to be received by other components of the Android OS.
+ * <p>
+ * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES}
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED =
+ "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
/**
* Broadcast sent when the device's UI has switch away from car mode back
@@ -75,6 +98,28 @@
* when the user exits car mode.
*/
public static String ACTION_EXIT_CAR_MODE = "android.app.action.EXIT_CAR_MODE";
+
+ /**
+ * Broadcast sent when the device's UI has switched away from car mode back to normal mode.
+ * Typically used by a car mode app, to dismiss itself when the user exits car mode.
+ * <p>
+ * In addition to the behavior for {@link #ACTION_EXIT_CAR_MODE}, this broadcast includes the
+ * package name of the app which requested to exit car mode in {@link #EXTRA_CALLING_PACKAGE}.
+ * If an app requested to enter car mode using {@link #enableCarMode(int, int)} and specified a
+ * priority this will be specified in the {@link #EXTRA_PRIORITY} when exiting car mode.
+ * <p>
+ * If {@link #DISABLE_CAR_MODE_ALL_PRIORITIES} is used when disabling car mode (i.e. this is
+ * initiated by the user via the persistent car mode notification), this broadcast is sent once
+ * for each priority level for which car mode is being disabled.
+ * <p>
+ * This is primarily intended to be received by other components of the Android OS.
+ * <p>
+ * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES}
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED =
+ "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
/**
* Broadcast sent when the device's UI has switched to desk mode,
@@ -97,6 +142,24 @@
*/
public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE";
+ /**
+ * String extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and
+ * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the package name of the app which
+ * requested to enter or exit car mode.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE";
+
+ /**
+ * Integer extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and
+ * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the priority level at which car mode
+ * is being disabled.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY";
+
/** @hide */
@IntDef(prefix = { "MODE_" }, value = {
MODE_NIGHT_AUTO,
@@ -126,10 +189,21 @@
private IUiModeManager mService;
+ /**
+ * Context required for getting the opPackageName of API caller; maybe be {@code null} if the
+ * old constructor marked with UnSupportedAppUsage is used.
+ */
+ private @Nullable Context mContext;
+
@UnsupportedAppUsage
/*package*/ UiModeManager() throws ServiceNotFoundException {
+ this(null /* context */);
+ }
+
+ /*package*/ UiModeManager(Context context) throws ServiceNotFoundException {
mService = IUiModeManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.UI_MODE_SERVICE));
+ mContext = context;
}
/**
@@ -152,6 +226,14 @@
*/
public static final int ENABLE_CAR_MODE_ALLOW_SLEEP = 0x0002;
+ /** @hide */
+ @IntDef(prefix = { "ENABLE_CAR_MODE_" }, value = {
+ ENABLE_CAR_MODE_GO_CAR_HOME,
+ ENABLE_CAR_MODE_ALLOW_SLEEP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EnableCarMode {}
+
/**
* Force device into car mode, like it had been placed in the car dock.
* This will cause the device to switch to the car home UI as part of
@@ -159,9 +241,54 @@
* @param flags Must be 0.
*/
public void enableCarMode(int flags) {
+ enableCarMode(DEFAULT_PRIORITY, flags);
+ }
+
+ /**
+ * Force device into car mode, like it had been placed in the car dock. This will cause the
+ * device to switch to the car home UI as part of the mode switch.
+ * <p>
+ * An app may request to enter car mode when the system is already in car mode. The app may
+ * specify a "priority" when entering car mode. The device will remain in car mode
+ * (i.e. {@link #getCurrentModeType()} is {@link Configuration#UI_MODE_TYPE_CAR}) as long as
+ * there is a priority level at which car mode have been enabled. For example assume app A
+ * enters car mode at priority level 100, and then app B enters car mode at the default priority
+ * (0). If app A exits car mode, the device will remain in car mode until app B exits car mode.
+ * <p>
+ * Specifying a priority level when entering car mode is important in cases where multiple apps
+ * on a device implement a car-mode {@link android.telecom.InCallService} (see
+ * {@link android.telecom.TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI}). The
+ * {@link android.telecom.InCallService} associated with the highest priority app which entered
+ * car mode will be bound to by Telecom and provided with information about ongoing calls on
+ * the device.
+ * <p>
+ * System apps holding the required permission can enable car mode when the app determines the
+ * correct conditions exist for that app to be in car mode. The device maker should ensure that
+ * where multiple apps exist on the device which can potentially enter car mode, appropriate
+ * priorities are used to ensure that calls delivered by the
+ * {@link android.telecom.InCallService} API are delivered to the highest priority app.
+ * If app A and app B can both potentially enable car mode, and it is desired that app B is the
+ * one which should receive call information, the priority for app B should be higher than the
+ * one for app A.
+ * <p>
+ * When an app uses a priority to enable car mode, they can disable car mode at the specified
+ * priority level using {@link #disableCarMode(int)}. An app may only enable car mode at a
+ * single priority.
+ * <p>
+ * Public apps are assumed to enter/exit car mode at {@link #DEFAULT_PRIORITY}.
+ *
+ * @param priority The declared priority for the caller.
+ * @param flags Car mode flags.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED)
+ public void enableCarMode(@IntRange(from = 0) int priority, @EnableCarMode int flags) {
if (mService != null) {
try {
- mService.enableCarMode(flags);
+ mService.enableCarMode(flags, priority,
+ mContext == null ? null : mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -176,15 +303,44 @@
* being in car mode).
*/
public static final int DISABLE_CAR_MODE_GO_HOME = 0x0001;
+
+ /**
+ * Flag for use with {@link #disableCarMode(int)}: Disables car mode at ALL priority levels.
+ * Primarily intended for use from {@link com.android.internal.app.DisableCarModeActivity} to
+ * provide the user with a means to exit car mode at all priority levels.
+ * @hide
+ */
+ public static final int DISABLE_CAR_MODE_ALL_PRIORITIES = 0x0002;
+
+ /** @hide */
+ @IntDef(prefix = { "DISABLE_CAR_MODE_" }, value = {
+ DISABLE_CAR_MODE_GO_HOME
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DisableCarMode {}
+
+ /**
+ * The default priority used for entering car mode.
+ * <p>
+ * Callers of the {@link UiModeManager#enableCarMode(int)} priority will be assigned the
+ * default priority.
+ * <p>
+ * System apps can specify a priority other than the default priority when using
+ * {@link UiModeManager#enableCarMode(int, int)} to enable car mode.
+ * @hide
+ */
+ @SystemApi
+ public static final int DEFAULT_PRIORITY = 0;
/**
* Turn off special mode if currently in car mode.
- * @param flags May be 0 or {@link #DISABLE_CAR_MODE_GO_HOME}.
+ * @param flags One of the disable car mode flags.
*/
- public void disableCarMode(int flags) {
+ public void disableCarMode(@DisableCarMode int flags) {
if (mService != null) {
try {
- mService.disableCarMode(flags);
+ mService.disableCarModeByCallingPackage(flags,
+ mContext == null ? null : mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 19f42b6..0be3eca 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1095,24 +1095,6 @@
}
/**
- * Get the Bluetooth alias of the remote device.
- * If Alias is null, get the Bluetooth name instead.
- *
- * @return the Bluetooth alias, or null if no alias or there was a problem
- * @hide
- * @see #getAlias()
- * @see #getName()
- */
- @UnsupportedAppUsage(publicAlternatives = "Use {@link #getName()} instead.")
- public String getAliasName() {
- String name = getAlias();
- if (name == null) {
- name = getName();
- }
- return name;
- }
-
- /**
* Get the most recent identified battery level of this Bluetooth device
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index cfb363a08..4e97627 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -16,8 +16,13 @@
package android.bluetooth;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -25,6 +30,8 @@
import android.os.RemoteException;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -40,6 +47,7 @@
*
* @hide
*/
+@SystemApi
public final class BluetoothPan implements BluetoothProfile {
private static final String TAG = "BluetoothPan";
private static final boolean DBG = true;
@@ -67,6 +75,7 @@
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
* receive.
*/
+ @SuppressLint("ActionValue")
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
@@ -76,19 +85,32 @@
* The local role of the PAN profile that the remote device is bound to.
* It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}.
*/
+ @SuppressLint("ActionValue")
public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ /** @hide */
+ @IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LocalPanRole {}
+
public static final int PAN_ROLE_NONE = 0;
/**
* The local device is acting as a Network Access Point.
*/
public static final int LOCAL_NAP_ROLE = 1;
- public static final int REMOTE_NAP_ROLE = 1;
/**
* The local device is acting as a PAN User.
*/
public static final int LOCAL_PANU_ROLE = 2;
+
+ /** @hide */
+ @IntDef({PAN_ROLE_NONE, REMOTE_NAP_ROLE, REMOTE_PANU_ROLE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RemotePanRole {}
+
+ public static final int REMOTE_NAP_ROLE = 1;
+
public static final int REMOTE_PANU_ROLE = 2;
/**
@@ -134,6 +156,8 @@
/**
* Create a BluetoothPan proxy object for interacting with the local
* Bluetooth Service which handles the Pan profile
+ *
+ * @hide
*/
@UnsupportedAppUsage
/*package*/ BluetoothPan(Context context, ServiceListener listener) {
@@ -235,7 +259,7 @@
* {@inheritDoc}
*/
@Override
- public List<BluetoothDevice> getConnectedDevices() {
+ public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothPan service = getService();
if (service != null && isEnabled()) {
@@ -252,6 +276,7 @@
/**
* {@inheritDoc}
+ * @hide
*/
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
@@ -273,7 +298,7 @@
* {@inheritDoc}
*/
@Override
- public int getConnectionState(BluetoothDevice device) {
+ public int getConnectionState(@Nullable BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -288,7 +313,11 @@
return BluetoothProfile.STATE_DISCONNECTED;
}
- @UnsupportedAppUsage
+ /**
+ * Turns on/off bluetooth tethering
+ *
+ * @param value is whether to enable or disable bluetooth tethering
+ */
public void setBluetoothTethering(boolean value) {
String pkgName = mContext.getOpPackageName();
if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
@@ -302,7 +331,11 @@
}
}
- @UnsupportedAppUsage
+ /**
+ * Determines whether tethering is enabled
+ *
+ * @return true if tethering is on, false if not or some error occurred
+ */
public boolean isTetheringOn() {
if (VDBG) log("isTetheringOn()");
final IBluetoothPan service = getService();
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index dabe0fd..f1ac765 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -20,9 +20,9 @@
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -43,6 +43,7 @@
* This extra represents the current connection state of the profile of the
* Bluetooth device.
*/
+ @SuppressLint("ActionValue")
String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
/**
@@ -51,6 +52,7 @@
* This extra represents the previous connection state of the profile of the
* Bluetooth device.
*/
+ @SuppressLint("ActionValue")
String EXTRA_PREVIOUS_STATE =
"android.bluetooth.profile.extra.PREVIOUS_STATE";
@@ -106,7 +108,7 @@
*
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @SystemApi
int PAN = 5;
/**
@@ -324,4 +326,54 @@
return "STATE_UNKNOWN";
}
}
+
+ /**
+ * Convert an integer value of profile ID into human readable string
+ *
+ * @param profile profile ID
+ * @return profile name as String, UNKOWN_PROFILE if the profile ID is not defined.
+ * @hide
+ */
+ static String getProfileName(int profile) {
+ switch(profile) {
+ case HEADSET:
+ return "HEADSET";
+ case A2DP:
+ return "A2DP";
+ case HID_HOST:
+ return "HID_HOST";
+ case PAN:
+ return "PAN";
+ case PBAP:
+ return "PBAP";
+ case GATT:
+ return "GATT";
+ case GATT_SERVER:
+ return "GATT_SERVER";
+ case MAP:
+ return "MAP";
+ case SAP:
+ return "SAP";
+ case A2DP_SINK:
+ return "A2DP_SINK";
+ case AVRCP_CONTROLLER:
+ return "AVRCP_CONTROLLER";
+ case AVRCP:
+ return "AVRCP";
+ case HEADSET_CLIENT:
+ return "HEADSET_CLIENT";
+ case PBAP_CLIENT:
+ return "PBAP_CLIENT";
+ case MAP_CLIENT:
+ return "MAP_CLIENT";
+ case HID_DEVICE:
+ return "HID_DEVICE";
+ case OPP:
+ return "OPP";
+ case HEARING_AID:
+ return "HEARING_AID";
+ default:
+ return "UNKNOWN_PROFILE";
+ }
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a12e4da..4b22166 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2424,10 +2424,10 @@
*
* @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
*/
- public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
- @Nullable String receiverPermission, @Nullable String receiverAppOp,
- @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
- int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+ public void sendOrderedBroadcast(@NonNull Intent intent, @Nullable String receiverPermission,
+ @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -5256,8 +5256,9 @@
*/
@SystemApi
@TestApi
+ @NonNull
public Context createPackageContextAsUser(
- String packageName, @CreatePackageOptions int flags, UserHandle user)
+ @NonNull String packageName, @CreatePackageOptions int flags, @NonNull UserHandle user)
throws PackageManager.NameNotFoundException {
if (Build.IS_ENG) {
throw new IllegalStateException("createPackageContextAsUser not overridden!");
@@ -5266,6 +5267,23 @@
}
/**
+ * Similar to {@link #createPackageContext(String, int)}, but for the own package with a
+ * different {@link UserHandle}. For example, {@link #getContentResolver()}
+ * will open any {@link Uri} as the given user.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @NonNull
+ public Context createContextAsUser(@NonNull UserHandle user, @CreatePackageOptions int flags) {
+ if (Build.IS_ENG) {
+ throw new IllegalStateException("createContextAsUser not overridden!");
+ }
+ return this;
+ }
+
+ /**
* Creates a context given an {@link android.content.pm.ApplicationInfo}.
*
* @hide
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 2b1b8eb..428aadb 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -898,6 +898,12 @@
/** @hide */
@Override
+ public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
+ return mBase.createContextAsUser(user, flags);
+ }
+
+ /** @hide */
+ @Override
@UnsupportedAppUsage
public Context createApplicationContext(ApplicationInfo application,
int flags) throws PackageManager.NameNotFoundException {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3cecd7f..1099d8b 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1565,7 +1565,7 @@
}
/** {@hide} */
- @SystemApi
+ @SystemApi @TestApi
public void setRequestDowngrade(boolean requestDowngrade) {
if (requestDowngrade) {
installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 28d9152..ce5fc3b 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -415,6 +415,17 @@
@ResolveInfoFlags int flags, int filterCallingUid, int userId);
/**
+ * Retrieve all activities that can be performed for the given intent.
+ * @param filterCallingUid The results will be filtered in the context of this UID instead
+ * of the calling UID.
+ * @see PackageManager#queryIntentActivities(Intent, int)
+ */
+ public abstract List<ResolveInfo> queryIntentActivities(
+ Intent intent, @Nullable String resolvedType, @ResolveInfoFlags int flags,
+ int filterCallingUid, int userId);
+
+
+ /**
* Retrieve all services that can be performed for the given intent.
* @see PackageManager#queryIntentServices(Intent, int)
*/
@@ -879,12 +890,6 @@
"android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS";
/**
- * Extra field name for the set of installed users for a given rollback package.
- */
- public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS =
- "android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS";
-
- /**
* Extra field name for the user id an install is associated with when
* enabling rollback.
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5c5c13d..c53b644 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -254,6 +254,8 @@
/** @hide */
public static final String APK_FILE_EXTENSION = ".apk";
+ /** @hide */
+ public static final String APEX_FILE_EXTENSION = ".apex";
/** @hide */
public static class NewPermissionInfo {
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 1b84f29..8c2a65f 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -24,7 +24,7 @@
interface IRollbackManager {
ParceledListSlice getAvailableRollbacks();
- ParceledListSlice getRecentlyExecutedRollbacks();
+ ParceledListSlice getRecentlyCommittedRollbacks();
void commitRollback(int rollbackId, in ParceledListSlice causePackages,
String callerPackageName, in IntentSender statusReceiver);
@@ -51,4 +51,7 @@
// Used by the staging manager to notify the RollbackManager of the apk
// session for a staged session.
void notifyStagedApkSession(int originalSessionId, int apkSessionId);
+
+ // For test purposes only.
+ void blockRollbackManager(long millis);
}
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 2014751..c89796d 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -76,10 +76,10 @@
private final boolean mIsApex;
/*
- * The list of users the package is installed for.
+ * The list of users for which snapshots have been saved.
*/
// NOTE: Not a part of the Parcelable representation of this object.
- private final IntArray mInstalledUsers;
+ private final IntArray mSnapshottedUsers;
/**
* A mapping between user and an inode of theirs CE data snapshot.
@@ -148,8 +148,8 @@
}
/** @hide */
- public IntArray getInstalledUsers() {
- return mInstalledUsers;
+ public IntArray getSnapshottedUsers() {
+ return mSnapshottedUsers;
}
/** @hide */
@@ -179,14 +179,14 @@
public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
VersionedPackage packageRolledBackTo,
@NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
- boolean isApex, @NonNull IntArray installedUsers,
+ boolean isApex, @NonNull IntArray snapshottedUsers,
@NonNull SparseLongArray ceSnapshotInodes) {
this.mVersionRolledBackFrom = packageRolledBackFrom;
this.mVersionRolledBackTo = packageRolledBackTo;
this.mPendingBackups = pendingBackups;
this.mPendingRestores = pendingRestores;
this.mIsApex = isApex;
- this.mInstalledUsers = installedUsers;
+ this.mSnapshottedUsers = snapshottedUsers;
this.mCeSnapshotInodes = ceSnapshotInodes;
}
@@ -196,7 +196,7 @@
this.mIsApex = in.readBoolean();
this.mPendingRestores = null;
this.mPendingBackups = null;
- this.mInstalledUsers = null;
+ this.mSnapshottedUsers = null;
this.mCeSnapshotInodes = null;
}
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 9a10a0c..73b8a48 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -114,7 +114,7 @@
})
public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
try {
- return mBinder.getRecentlyExecutedRollbacks().getList();
+ return mBinder.getRecentlyCommittedRollbacks().getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -250,4 +250,25 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Block the RollbackManager for a specified amount of time.
+ * This API is meant to facilitate testing of race conditions in
+ * RollbackManager. Blocks RollbackManager from processing anything for
+ * the given number of milliseconds.
+ *
+ * @param millis number of milliseconds to block the RollbackManager for
+ * @throws SecurityException if the caller does not have appropriate permissions.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
+ @TestApi
+ public void blockRollbackManager(long millis) {
+ try {
+ mBinder.blockRollbackManager(millis);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 75af41c..56bacf2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -52,13 +52,12 @@
import android.os.ServiceSpecificException;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
@@ -711,6 +710,12 @@
@Deprecated
public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused.
+ // Deprecated constants for return values of startUsingNetworkFeature. They used to live
+ // in com.android.internal.telephony.PhoneConstants until they were made inaccessible.
+ private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0;
+ private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED = 1;
+ private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED = 3;
+
/** {@hide} */
public static final int MAX_RADIO_TYPE = TYPE_TEST;
@@ -1407,7 +1412,7 @@
if (netCap == null) {
Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " +
feature);
- return PhoneConstants.APN_REQUEST_FAILED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
}
NetworkRequest request = null;
@@ -1417,9 +1422,9 @@
Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest);
renewRequestLocked(l);
if (l.currentNetwork != null) {
- return PhoneConstants.APN_ALREADY_ACTIVE;
+ return DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE;
} else {
- return PhoneConstants.APN_REQUEST_STARTED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
}
}
@@ -1427,10 +1432,10 @@
}
if (request != null) {
Log.d(TAG, "starting startUsingNetworkFeature for request " + request);
- return PhoneConstants.APN_REQUEST_STARTED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
} else {
Log.d(TAG, " request Failed");
- return PhoneConstants.APN_REQUEST_FAILED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
}
}
@@ -2149,19 +2154,14 @@
@Deprecated
@UnsupportedAppUsage
public boolean getMobileDataEnabled() {
- IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE);
- if (b != null) {
- try {
- ITelephony it = ITelephony.Stub.asInterface(b);
- int subId = SubscriptionManager.getDefaultDataSubscriptionId();
- Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
- boolean retVal = it.isUserDataEnabled(subId);
- Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
- + " retVal=" + retVal);
- return retVal;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ if (tm != null) {
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
+ boolean retVal = tm.createForSubscriptionId(subId).isDataEnabled();
+ Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
+ + " retVal=" + retVal);
+ return retVal;
}
Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
return false;
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 2af82d7..143467b 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -16,6 +16,10 @@
package android.net;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.net.StaticIpConfiguration;
import android.os.Parcel;
@@ -27,13 +31,17 @@
* A class representing a configured network.
* @hide
*/
-public class IpConfiguration implements Parcelable {
+@SystemApi
+public final class IpConfiguration implements Parcelable {
private static final String TAG = "IpConfiguration";
+ // This enum has been used by apps through reflection for many releases.
+ // Therefore they can't just be removed. Duplicating these constants to
+ // give an alternate SystemApi is a worse option than exposing them.
+ @SuppressLint("Enum")
public enum IpAssignment {
/* Use statically configured IP settings. Configuration can be accessed
* with staticIpConfiguration */
- @UnsupportedAppUsage
STATIC,
/* Use dynamically configured IP settings */
DHCP,
@@ -42,14 +50,19 @@
UNASSIGNED
}
+ /** @hide */
public IpAssignment ipAssignment;
+ /** @hide */
public StaticIpConfiguration staticIpConfiguration;
+ // This enum has been used by apps through reflection for many releases.
+ // Therefore they can't just be removed. Duplicating these constants to
+ // give an alternate SystemApi is a worse option than exposing them.
+ @SuppressLint("Enum")
public enum ProxySettings {
/* No proxy is to be used. Any existing proxy settings
* should be cleared. */
- @UnsupportedAppUsage
NONE,
/* Use statically configured proxy. Configuration can be accessed
* with httpProxy. */
@@ -62,8 +75,10 @@
PAC
}
+ /** @hide */
public ProxySettings proxySettings;
+ /** @hide */
@UnsupportedAppUsage
public ProxyInfo httpProxy;
@@ -83,6 +98,7 @@
init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
}
+ /** @hide */
@UnsupportedAppUsage
public IpConfiguration(IpAssignment ipAssignment,
ProxySettings proxySettings,
@@ -91,7 +107,7 @@
init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
}
- public IpConfiguration(IpConfiguration source) {
+ public IpConfiguration(@NonNull IpConfiguration source) {
this();
if (source != null) {
init(source.ipAssignment, source.proxySettings,
@@ -99,35 +115,35 @@
}
}
- public IpAssignment getIpAssignment() {
+ public @NonNull IpAssignment getIpAssignment() {
return ipAssignment;
}
- public void setIpAssignment(IpAssignment ipAssignment) {
+ public void setIpAssignment(@NonNull IpAssignment ipAssignment) {
this.ipAssignment = ipAssignment;
}
- public StaticIpConfiguration getStaticIpConfiguration() {
+ public @Nullable StaticIpConfiguration getStaticIpConfiguration() {
return staticIpConfiguration;
}
- public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
+ public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) {
this.staticIpConfiguration = staticIpConfiguration;
}
- public ProxySettings getProxySettings() {
+ public @NonNull ProxySettings getProxySettings() {
return proxySettings;
}
- public void setProxySettings(ProxySettings proxySettings) {
+ public void setProxySettings(@NonNull ProxySettings proxySettings) {
this.proxySettings = proxySettings;
}
- public ProxyInfo getHttpProxy() {
+ public @Nullable ProxyInfo getHttpProxy() {
return httpProxy;
}
- public void setHttpProxy(ProxyInfo httpProxy) {
+ public void setHttpProxy(@Nullable ProxyInfo httpProxy) {
this.httpProxy = httpProxy;
}
@@ -175,13 +191,19 @@
83 * httpProxy.hashCode();
}
- /** Implement the Parcelable interface */
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
public int describeContents() {
return 0;
}
- /** Implement the Parcelable interface */
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(ipAssignment.name());
dest.writeString(proxySettings.name());
dest.writeParcelable(staticIpConfiguration, flags);
@@ -189,7 +211,7 @@
}
/** Implement the Parcelable interface */
- public static final @android.annotation.NonNull Creator<IpConfiguration> CREATOR =
+ public static final @NonNull Creator<IpConfiguration> CREATOR =
new Creator<IpConfiguration>() {
public IpConfiguration createFromParcel(Parcel in) {
IpConfiguration config = new IpConfiguration();
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index a101da7..9af1407 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -16,17 +16,20 @@
package android.net;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiSsid;
+import android.net.wifi.WifiManager;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -48,6 +51,13 @@
/** A wifi network, for which {@link #wifiKey} will be populated. */
public static final int TYPE_WIFI = 1;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"TYPE_"}, value = {
+ TYPE_WIFI
+ })
+ public @interface NetworkType {}
+
/**
* The type of this network.
* @see #TYPE_WIFI
@@ -65,26 +75,28 @@
*
* @return A new {@link NetworkKey} instance or <code>null</code> if the given
* {@link ScanResult} instance is malformed.
- * @hide
*/
@Nullable
public static NetworkKey createFromScanResult(@Nullable ScanResult result) {
- if (result != null && result.wifiSsid != null) {
- final String ssid = result.wifiSsid.toString();
- final String bssid = result.BSSID;
- if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
- && !TextUtils.isEmpty(bssid)) {
- WifiKey wifiKey;
- try {
- wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Unable to create WifiKey.", e);
- return null;
- }
- return new NetworkKey(wifiKey);
- }
+ if (result == null) {
+ return null;
}
- return null;
+ final String ssid = result.SSID;
+ if (TextUtils.isEmpty(ssid) || ssid.equals(WifiManager.UNKNOWN_SSID)) {
+ return null;
+ }
+ final String bssid = result.BSSID;
+ if (TextUtils.isEmpty(bssid)) {
+ return null;
+ }
+
+ try {
+ final WifiKey wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid);
+ return new NetworkKey(wifiKey);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Unable to create WifiKey.", e);
+ return null;
+ }
}
/**
@@ -100,7 +112,7 @@
if (wifiInfo != null) {
final String ssid = wifiInfo.getSSID();
final String bssid = wifiInfo.getBSSID();
- if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
+ if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiManager.UNKNOWN_SSID)
&& !TextUtils.isEmpty(bssid)) {
WifiKey wifiKey;
try {
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
index 1ab6335..13f2994 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/core/java/android/net/NetworkScore.java
@@ -154,4 +154,9 @@
}
return true;
}
+
+ /** Convert to a string */
+ public String toString() {
+ return "NetworkScore[" + mExtensions.toString() + "]";
+ }
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 50dd468..f6dc525 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -17,7 +17,9 @@
package android.net;
import android.Manifest.permission;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -25,13 +27,16 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Class that manages communication between network subsystems and a network scorer.
@@ -50,19 +55,25 @@
@SystemApi
@SystemService(Context.NETWORK_SCORE_SERVICE)
public class NetworkScoreManager {
+ private static final String TAG = "NetworkScoreManager";
+
/**
* Activity action: ask the user to change the active network scorer. This will show a dialog
* that asks the user whether they want to replace the current active scorer with the one
* specified in {@link #EXTRA_PACKAGE_NAME}. The activity will finish with RESULT_OK if the
* active scorer was changed or RESULT_CANCELED if it failed for any reason.
+ * @deprecated No longer sent.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
/**
* Extra used with {@link #ACTION_CHANGE_ACTIVE} to specify the new scorer package. Set with
* {@link android.content.Intent#putExtra(String, String)}.
+ * @deprecated No longer sent.
*/
+ @Deprecated
public static final String EXTRA_PACKAGE_NAME = "packageName";
/**
@@ -73,7 +84,9 @@
* configured by the user as well as any open networks.
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
@@ -81,7 +94,9 @@
* Extra used with {@link #ACTION_SCORE_NETWORKS} to specify the networks to be scored, as an
* array of {@link NetworkKey}s. Can be obtained with
* {@link android.content.Intent#getParcelableArrayExtra(String)}}.
+ * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead.
*/
+ @Deprecated
public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
/**
@@ -285,7 +300,7 @@
* @throws SecurityException if the caller is not the active scorer.
*/
@RequiresPermission(android.Manifest.permission.SCORE_NETWORKS)
- public boolean updateScores(ScoredNetwork[] networks) throws SecurityException {
+ public boolean updateScores(@NonNull ScoredNetwork[] networks) throws SecurityException {
try {
return mService.updateScores(networks);
} catch (RemoteException e) {
@@ -359,13 +374,21 @@
/**
* Request scoring for networks.
*
- * @return true if the broadcast was sent, or false if there is no active scorer.
+ * <p>
+ * Note: The results (i.e scores) for these networks, when available will be provided via the
+ * callback registered with {@link #registerNetworkScoreCallback(int, int, Executor,
+ * NetworkScoreCallback)}. The calling module is responsible for registering a callback to
+ * receive the results before requesting new scores via this API.
+ *
+ * @return true if the request was successfully sent, or false if there is no active scorer.
* @throws SecurityException if the caller does not hold the
* {@link permission#REQUEST_NETWORK_SCORES} permission.
+ *
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
- public boolean requestScores(NetworkKey[] networks) throws SecurityException {
+ public boolean requestScores(@NonNull NetworkKey[] networks) throws SecurityException {
try {
return mService.requestScores(networks);
} catch (RemoteException e) {
@@ -431,6 +454,88 @@
}
/**
+ * Base class for network score cache callback. Should be extended by applications and set
+ * when calling {@link #registerNetworkScoreCallback(int, int, NetworkScoreCallback,
+ * Executor)}
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkScoreCallback {
+ /**
+ * Called when a new set of network scores are available.
+ * This is triggered in response when the client invokes
+ * {@link #requestScores(NetworkKey[])} to score a new set of networks.
+ *
+ * @param networks List of {@link ScoredNetwork} containing updated scores.
+ */
+ void updateScores(@NonNull List<ScoredNetwork> networks);
+
+ /**
+ * Invokes when all the previously provided scores are no longer valid.
+ */
+ void clearScores();
+ }
+
+ /**
+ * Callback proxy for {@link NetworkScoreCallback} objects.
+ */
+ private class NetworkScoreCallbackProxy extends INetworkScoreCache.Stub {
+ private final Executor mExecutor;
+ private final NetworkScoreCallback mCallback;
+
+ NetworkScoreCallbackProxy(Executor executor, NetworkScoreCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void updateScores(@NonNull List<ScoredNetwork> networks) {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mCallback.updateScores(networks);
+ });
+ }
+
+ @Override
+ public void clearScores() {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mCallback.clearScores();
+ });
+ }
+ }
+
+ /**
+ * Register a network score callback.
+ *
+ * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
+ * @param filterType the {@link CacheUpdateFilter} to apply
+ * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the
+ * scores change.
+ * @param executor The executor on which to execute the callbacks.
+ * @throws SecurityException if the caller does not hold the
+ * {@link permission#REQUEST_NETWORK_SCORES} permission.
+ * @throws IllegalArgumentException if a callback is already registered for this type.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
+ public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType,
+ @CacheUpdateFilter int filterType,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull NetworkScoreCallback callback) throws SecurityException {
+ if (callback == null || executor == null) {
+ throw new IllegalArgumentException("callback / executor cannot be null");
+ }
+ Log.v(TAG, "registerNetworkScoreCallback: callback=" + callback + ", executor="
+ + executor);
+ // Use the @hide method.
+ registerNetworkScoreCache(
+ networkType, new NetworkScoreCallbackProxy(executor, callback), filterType);
+ }
+
+ /**
* Determine whether the application with the given UID is the enabled scorer.
*
* @param callingUid the UID to check
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index 807c467..9d92db4 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -16,7 +16,8 @@
package android.net;
-
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -89,6 +90,15 @@
}
/**
+ * Construct a {@link ProxyInfo} object that will download and run the PAC script at the
+ * specified URL and port.
+ */
+ @NonNull
+ public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) {
+ return new ProxyInfo(pacUrl, port);
+ }
+
+ /**
* Create a ProxyProperties that points at a HTTP Proxy.
* @hide
*/
@@ -105,7 +115,7 @@
* Create a ProxyProperties that points at a PAC URL.
* @hide
*/
- public ProxyInfo(Uri pacFileUrl) {
+ public ProxyInfo(@NonNull Uri pacFileUrl) {
mHost = LOCAL_HOST;
mPort = LOCAL_PORT;
mExclusionList = LOCAL_EXCL_LIST;
@@ -132,7 +142,7 @@
* Only used in PacManager after Local Proxy is bound.
* @hide
*/
- public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
+ public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) {
mHost = LOCAL_HOST;
mPort = localProxyPort;
mExclusionList = LOCAL_EXCL_LIST;
@@ -159,11 +169,10 @@
mPacFileUrl = Uri.EMPTY;
}
- // copy constructor instead of clone
/**
- * @hide
+ * A copy constructor to hold proxy properties.
*/
- public ProxyInfo(ProxyInfo source) {
+ public ProxyInfo(@Nullable ProxyInfo source) {
if (source != null) {
mHost = source.getHost();
mPort = source.getPort();
@@ -226,12 +235,13 @@
* comma separated
* @hide
*/
+ @Nullable
public String getExclusionListAsString() {
return mExclusionList;
}
/**
- * @hide
+ * Return true if the pattern of proxy is valid, otherwise return false.
*/
public boolean isValid() {
if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index f789b72..2ac3def 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1275,7 +1275,13 @@
/**
* Closes the given object quietly, ignoring any checked exceptions. Does
* nothing if the given object is {@code null}.
+ *
+ * @deprecated This method may suppress potentially significant exceptions, particularly when
+ * closing writable resources. With a writable resource, a failure thrown from {@code close()}
+ * should be considered as significant as a failure thrown from a write method because it may
+ * indicate a failure to flush bytes to the underlying resource.
*/
+ @Deprecated
public static void closeQuietly(@Nullable AutoCloseable closeable) {
IoUtils.closeQuietly(closeable);
}
@@ -1283,7 +1289,13 @@
/**
* Closes the given object quietly, ignoring any checked exceptions. Does
* nothing if the given object is {@code null}.
+ *
+ * @deprecated This method may suppress potentially significant exceptions, particularly when
+ * closing writable resources. With a writable resource, a failure thrown from {@code close()}
+ * should be considered as significant as a failure thrown from a write method because it may
+ * indicate a failure to flush bytes to the underlying resource.
*/
+ @Deprecated
public static void closeQuietly(@Nullable FileDescriptor fd) {
IoUtils.closeQuietly(fd);
}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 9af9eda..a99bdabe 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -28,15 +28,14 @@
* A Handler allows you to send and process {@link Message} and Runnable
* objects associated with a thread's {@link MessageQueue}. Each Handler
* instance is associated with a single thread and that thread's message
- * queue. When you create a new Handler, it is bound to the thread /
- * message queue of the thread that is creating it -- from that point on,
- * it will deliver messages and runnables to that message queue and execute
- * them as they come out of the message queue.
- *
+ * queue. When you create a new Handler it is bound to a {@link Looper}.
+ * It will deliver messages and runnables to that Looper's message
+ * queue and execute them on that Looper's thread.
+ *
* <p>There are two main uses for a Handler: (1) to schedule messages and
* runnables to be executed at some point in the future; and (2) to enqueue
* an action to be performed on a different thread than your own.
- *
+ *
* <p>Scheduling messages is accomplished with the
* {@link #post}, {@link #postAtTime(Runnable, long)},
* {@link #postDelayed}, {@link #sendEmptyMessage},
@@ -114,7 +113,18 @@
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
+ *
+ * @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs
+ * where operations are silently lost (if the Handler is not expecting new tasks and quits),
+ * crashes (if a handler is sometimes created on a thread without a Looper active), or race
+ * conditions, where the thread a handler is associated with is not what the author
+ * anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper
+ * explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or
+ * similar. If the implicit thread local behavior is required for compatibility, use
+ * {@code new Handler(Looper.myLooper())} to make it clear to readers.
+ *
*/
+ @Deprecated
public Handler() {
this(null, false);
}
@@ -128,7 +138,17 @@
* so an exception is thrown.
*
* @param callback The callback interface in which to handle messages, or null.
+ *
+ * @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs
+ * where operations are silently lost (if the Handler is not expecting new tasks and quits),
+ * crashes (if a handler is sometimes created on a thread without a Looper active), or race
+ * conditions, where the thread a handler is associated with is not what the author
+ * anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper
+ * explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or
+ * similar. If the implicit thread local behavior is required for compatibility, use
+ * {@code new Handler(Looper.myLooper(), callback)} to make it clear to readers.
*/
+ @Deprecated
public Handler(@Nullable Callback callback) {
this(callback, false);
}
diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java
new file mode 100644
index 0000000..aeb6589
--- /dev/null
+++ b/core/java/android/os/HidlMemory.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 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.os;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * An abstract representation of a memory block, as representing by the HIDL system.
+ *
+ * The block is defined by a {name, size, handle} tuple, where the name is used to determine how to
+ * interpret the handle. The underlying handle is assumed to be owned by this instance and will be
+ * closed as soon as {@link #close()} is called on this instance, or this instance has been
+ * finalized (the latter supports using it in a shared manner without having to worry about who owns
+ * this instance, the former is more efficient resource-wise and is recommended for most use-cases).
+ * Note, however, that ownership of the handle does not necessarily imply ownership of the
+ * underlying file descriptors - the underlying handle may or may not own them. If you want the
+ * underlying handle to outlive this instance, call {@link #releaseHandle()} to obtain the handle
+ * and detach the ownership relationship.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class HidlMemory implements Closeable {
+ private final @NonNull String mName;
+ private final long mSize;
+ private @Nullable NativeHandle mHandle;
+ private long mNativeContext; // For use of native code.
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the IMapper service used to resolve the handle (e.g. "ashmem").
+ * @param size The (non-negative) size in bytes of the memory block.
+ * @param handle The handle. May be null. This instance will own the handle and will close it
+ * as soon as {@link #close()} is called or the object is destroyed. This, this
+ * handle instance should generally not be shared with other clients.
+ */
+ public HidlMemory(@NonNull String name, @IntRange(from = 0) long size,
+ @Nullable NativeHandle handle) {
+ mName = name;
+ mSize = size;
+ mHandle = handle;
+ }
+
+ /**
+ * Create a copy of this instance, where the underlying handle (and its file descriptors) have
+ * been duplicated.
+ */
+ @NonNull
+ public HidlMemory dup() throws IOException {
+ return new HidlMemory(mName, mSize, mHandle != null ? mHandle.dup() : null);
+ }
+
+ /**
+ * Close the underlying native handle. No-op if handle is null or has been released using {@link
+ * #releaseHandle()}.
+ */
+ @Override
+ public void close() throws IOException {
+ if (mHandle != null) {
+ mHandle.close();
+ }
+ }
+
+ /**
+ * Disowns the underlying handle and returns it. This object becomes invalid.
+ *
+ * @return The underlying handle.
+ */
+ @NonNull
+ public NativeHandle releaseHandle() {
+ NativeHandle handle = mHandle;
+ mHandle = null;
+ return handle;
+ }
+
+ /**
+ * Gets the name, which represents how the handle is to be interpreted.
+ *
+ * @return The name.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the size of the block, in bytes.
+ *
+ * @return The size.
+ */
+ public long getSize() {
+ return mSize;
+ }
+
+ /**
+ * Gets a native handle. The actual interpretation depends on the name and is implementation
+ * defined.
+ *
+ * @return The native handle.
+ */
+ @Nullable
+ public NativeHandle getHandle() {
+ return mHandle;
+ }
+
+ @Override
+ protected void finalize() {
+ try {
+ close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ nativeFinalize();
+ }
+ }
+
+ private native void nativeFinalize();
+}
diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java
new file mode 100644
index 0000000..b08822d
--- /dev/null
+++ b/core/java/android/os/HidlMemoryUtil.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 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.os;
+
+import static android.system.OsConstants.MAP_SHARED;
+import static android.system.OsConstants.PROT_READ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides utilities for dealing with HidlMemory.
+ *
+ * @hide
+ */
+public final class HidlMemoryUtil {
+ static private final String TAG = "HidlMemoryUtil";
+
+ private HidlMemoryUtil() {
+ }
+
+ /**
+ * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte array.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteArrayToHidlMemory(@NonNull byte[] input) {
+ return byteArrayToHidlMemory(input, null);
+ }
+
+ /**
+ * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte array.
+ * @param name An optional name for the ashmem region.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteArrayToHidlMemory(@NonNull byte[] input, @Nullable String name) {
+ Preconditions.checkNotNull(input);
+
+ if (input.length == 0) {
+ return new HidlMemory("ashmem", 0, null);
+ }
+
+ try {
+ SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length);
+ ByteBuffer buffer = shmem.mapReadWrite();
+ buffer.put(input);
+ shmem.unmap(buffer);
+ NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+ return new HidlMemory("ashmem", input.length, handle);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte list.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteListToHidlMemory(@NonNull List<Byte> input) {
+ return byteListToHidlMemory(input, null);
+ }
+
+ /**
+ * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte list.
+ * @param name An optional name for the ashmem region.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteListToHidlMemory(@NonNull List<Byte> input, @Nullable String name) {
+ Preconditions.checkNotNull(input);
+
+ if (input.isEmpty()) {
+ return new HidlMemory("ashmem", 0, null);
+ }
+
+ try {
+ SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size());
+ ByteBuffer buffer = shmem.mapReadWrite();
+ for (Byte b : input) {
+ buffer.put(b);
+ }
+ shmem.unmap(buffer);
+ NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+ return new HidlMemory("ashmem", input.size(), handle);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies all data from a HidlMemory instance into a byte array.
+ *
+ * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+ * {@link Integer#MAX_VALUE}.
+ * @return A byte array, containing a copy of the input.
+ */
+ public static @NonNull
+ byte[] hidlMemoryToByteArray(@NonNull HidlMemory mem) {
+ Preconditions.checkNotNull(mem);
+ Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+ "Memory size");
+ Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+ "Unsupported memory type: %s", mem.getName());
+
+ if (mem.getSize() == 0) {
+ return new byte[0];
+ }
+
+ ByteBuffer buffer = getBuffer(mem);
+ byte[] result = new byte[buffer.remaining()];
+ buffer.get(result);
+ return result;
+ }
+
+ /**
+ * Copies all data from a HidlMemory instance into a byte list.
+ *
+ * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+ * {@link Integer#MAX_VALUE}.
+ * @return A byte list, containing a copy of the input.
+ */
+ @SuppressLint("ConcreteCollection")
+ public static @NonNull
+ ArrayList<Byte> hidlMemoryToByteList(@NonNull HidlMemory mem) {
+ Preconditions.checkNotNull(mem);
+ Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+ "Memory size");
+ Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+ "Unsupported memory type: %s", mem.getName());
+
+ if (mem.getSize() == 0) {
+ return new ArrayList<>();
+ }
+
+ ByteBuffer buffer = getBuffer(mem);
+
+ ArrayList<Byte> result = new ArrayList<>(buffer.remaining());
+ while (buffer.hasRemaining()) {
+ result.add(buffer.get());
+ }
+ return result;
+ }
+
+ private static ByteBuffer getBuffer(@NonNull HidlMemory mem) {
+ try {
+ final int size = (int) mem.getSize();
+
+ if (size == 0) {
+ return ByteBuffer.wrap(new byte[0]);
+ }
+
+ NativeHandle handle = mem.getHandle();
+
+ final long address = Os.mmap(0, size, PROT_READ, MAP_SHARED, handle.getFileDescriptor(),
+ 0);
+ return new DirectByteBuffer(size, address, handle.getFileDescriptor(), () -> {
+ try {
+ Os.munmap(address, size);
+ } catch (ErrnoException e) {
+ Log.wtf(TAG, e);
+ }
+ }, true);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 2c453bf..154227b2 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -92,6 +92,14 @@
* @throws IndexOutOfBoundsException when offset is out of this HwBlob
*/
public native final String getString(long offset);
+ /**
+ * For embedded fields that follow a two-step approach for reading, first obtain their field
+ * handle using this method, and pass that field handle to the respective
+ * HwParcel.readEmbedded*() method.
+ * @param offset The field offset.
+ * @return The field handle.
+ */
+ public native final long getFieldHandle(long offset);
/**
* Copy the blobs data starting from the given byte offset into the range, copying
@@ -312,6 +320,20 @@
public native final void putBlob(long offset, HwBlob blob);
/**
+ * Writes a HidlMemory instance (without duplicating the underlying file descriptors) at an
+ * offset.
+ *
+ * @param offset location to write value
+ * @param mem a {@link HidlMemory} instance to write
+ * @throws IndexOutOfBoundsException when [offset, offset + sizeof(jobject)] is out of range
+ */
+ public final void putHidlMemory(long offset, @NonNull HidlMemory mem) {
+ putNativeHandle(offset + 0 /* offset of 'handle' field. */, mem.getHandle());
+ putInt64(offset + 16 /* offset of 'size' field. */, mem.getSize());
+ putString(offset + 24 /* offset of 'name' field. */, mem.getName());
+ }
+
+ /**
* @return current handle of HwBlob for reference in a parcelled binder transaction
*/
public native final long handle();
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 5e8929c..9786f16 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -324,6 +324,15 @@
public native final void writeStrongBinder(IHwBinder binder);
/**
+ * Write a HidlMemory object (without duplicating the underlying file descriptors) to the end
+ * of the parcel.
+ *
+ * @param memory value to write
+ */
+ @FastNative
+ public native final void writeHidlMemory(@NonNull HidlMemory memory);
+
+ /**
* Checks to make sure that the interface name matches the name written by the parcel
* sender by writeInterfaceToken
*
@@ -582,6 +591,38 @@
public native final IHwBinder readStrongBinder();
/**
+ * Reads a HidlMemory value (without duplicating the underlying file
+ * descriptors) from the parcel. These file descriptors will only
+ * be open for the duration that the binder window is open. If they
+ * are needed further, you must call {@link HidlMemory#dup()}, which makes you also
+ * responsible for calling {@link HidlMemory#close()}.
+ *
+ * @return HidlMemory object read from parcel.
+ * @throws IllegalArgumentException if the parcel has no more data or is otherwise corrupt.
+ */
+ @FastNative
+ @NonNull
+ public native final HidlMemory readHidlMemory();
+
+ /**
+ * Reads an embedded HidlMemory (without duplicating the underlying
+ * file descriptors) from the parcel. These file descriptors will only
+ * be open for the duration that the binder window is open. If they
+ * are needed further, you must call {@link HidlMemory#dup()}. You
+ * do not need to call close on the HidlMemory returned from this.
+ *
+ * @param fieldHandle handle of the field, obtained from the {@link HwBlob}.
+ * @param parentHandle parentHandle from which to read the embedded object
+ * @param offset offset into parent
+ * @return a {@link HidlMemory} instance parsed from the parcel
+ * @throws IllegalArgumentException if the parcel has no more data
+ */
+ @FastNative
+ @NonNull
+ public native final @Nullable
+ HidlMemory readEmbeddedHidlMemory(long fieldHandle, long parentHandle, long offset);
+
+ /**
* Read opaque segment of data as a blob.
* @return blob of size expectedSize
* @throws IllegalArgumentException if the parcel has no more data
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 3222fc4..d468972 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -112,10 +112,12 @@
/**
* Initialize the current thread as a looper, marking it as an
- * application's main looper. The main looper for your application
- * is created by the Android environment, so you should never need
- * to call this function yourself. See also: {@link #prepare()}
+ * application's main looper. See also: {@link #prepare()}
+ *
+ * @deprecated The main looper for your application is created by the Android environment,
+ * so you should never need to call this function yourself.
*/
+ @Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 8b0ffe1..f08e1ff 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -26,6 +26,9 @@
import com.android.internal.annotations.GuardedBy;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
import libcore.util.HexEncoding;
import java.nio.charset.StandardCharsets;
@@ -93,18 +96,43 @@
}
}
+ // The one-argument version of native_get used to be a regular native function. Nowadays,
+ // we use the two-argument form of native_get all the time, but we can't just delete the
+ // one-argument overload: apps use it via reflection, as the UnsupportedAppUsage annotation
+ // indicates. Let's just live with having a Java function with a very unusual name.
@UnsupportedAppUsage
- private static native String native_get(String key);
+ private static String native_get(String key) {
+ return native_get(key, "");
+ }
+
+ @FastNative
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static native String native_get(String key, String def);
+ @FastNative
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static native int native_get_int(String key, int def);
+ @FastNative
@UnsupportedAppUsage
private static native long native_get_long(String key, long def);
+ @FastNative
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static native boolean native_get_boolean(String key, boolean def);
+
+ @FastNative
+ private static native long native_find(String name);
+ @FastNative
+ private static native String native_get(long handle);
+ @CriticalNative
+ private static native int native_get_int(long handle, int def);
+ @CriticalNative
+ private static native long native_get_long(long handle, long def);
+ @CriticalNative
+ private static native boolean native_get_boolean(long handle, boolean def);
+
+ // _NOT_ FastNative: native_set performs IPC and can block
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static native void native_set(String key, String def);
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static native void native_add_change_callback();
private static native void native_report_sysprop_change();
@@ -229,25 +257,27 @@
@SuppressWarnings("unused") // Called from native code.
private static void callChangeCallbacks() {
+ ArrayList<Runnable> callbacks = null;
synchronized (sChangeCallbacks) {
//Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
if (sChangeCallbacks.size() == 0) {
return;
}
- ArrayList<Runnable> callbacks = new ArrayList<Runnable>(sChangeCallbacks);
- final long token = Binder.clearCallingIdentity();
- try {
- for (int i = 0; i < callbacks.size(); i++) {
- try {
- callbacks.get(i).run();
- } catch (Throwable t) {
- Log.wtf(TAG, "Exception in SystemProperties change callback", t);
- // Ignore and try to go on.
- }
+ callbacks = new ArrayList<Runnable>(sChangeCallbacks);
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ for (int i = 0; i < callbacks.size(); i++) {
+ try {
+ callbacks.get(i).run();
+ } catch (Throwable t) {
+ // Ignore and try to go on. Don't use wtf here: that
+ // will cause the process to exit on some builds and break tests.
+ Log.e(TAG, "Exception in SystemProperties change callback", t);
}
- } finally {
- Binder.restoreCallingIdentity(token);
}
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
@@ -284,4 +314,60 @@
@UnsupportedAppUsage
private SystemProperties() {
}
+
+ /**
+ * Look up a property location by name.
+ * @name name of the property
+ * @return property handle or {@code null} if property isn't set
+ * @hide
+ */
+ @Nullable public static Handle find(@NonNull String name) {
+ long nativeHandle = native_find(name);
+ if (nativeHandle == 0) {
+ return null;
+ }
+ return new Handle(nativeHandle);
+ }
+
+ /**
+ * Handle to a pre-located property. Looking up a property handle in advance allows
+ * for optimal repeated lookup of a single property.
+ * @hide
+ */
+ public static final class Handle {
+
+ private final long mNativeHandle;
+
+ /**
+ * @return Value of the property
+ */
+ @NonNull public String get() {
+ return native_get(mNativeHandle);
+ }
+ /**
+ * @param def default value
+ * @return value or {@code def} on parse error
+ */
+ public int getInt(int def) {
+ return native_get_int(mNativeHandle, def);
+ }
+ /**
+ * @param def default value
+ * @return value or {@code def} on parse error
+ */
+ public long getLong(long def) {
+ return native_get_long(mNativeHandle, def);
+ }
+ /**
+ * @param def default value
+ * @return value or {@code def} on parse error
+ */
+ public boolean getBoolean(boolean def) {
+ return native_get_boolean(mNativeHandle, def);
+ }
+
+ private Handle(long nativeHandle) {
+ mNativeHandle = nativeHandle;
+ }
+ }
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 82a3c40..391f3a2 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -43,8 +43,6 @@
import android.text.TextUtils;
import android.util.Log;
-import com.android.internal.telephony.PhoneConstants;
-
import java.util.List;
/**
@@ -610,7 +608,7 @@
* if the contact is unknown.
* @param context the context used to get the ContentResolver
* @param number the phone number to be added to the calls db
- * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+ * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which
* is set by the network and denotes the number presenting rules for
* "allowed", "payphone", "restricted" or "unknown"
* @param callType enumerated values for "incoming", "outgoing", or "missed"
@@ -645,7 +643,7 @@
* @param number the phone number to be added to the calls db
* @param viaNumber the secondary number that the incoming call received with. If the
* call was received with the SIM assigned number, then this field must be ''.
- * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+ * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which
* is set by the network and denotes the number presenting rules for
* "allowed", "payphone", "restricted" or "unknown"
* @param callType enumerated values for "incoming", "outgoing", or "missed"
@@ -686,7 +684,7 @@
* if it was outgoing. Otherwise it is ''.
* @param viaNumber the secondary number that the incoming call received with. If the
* call was received with the SIM assigned number, then this field must be ''.
- * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+ * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which
* is set by the network and denotes the number presenting rules for
* "allowed", "payphone", "restricted" or "unknown"
* @param callType enumerated values for "incoming", "outgoing", or "missed"
@@ -1048,22 +1046,22 @@
/**
* Remap network specified number presentation types
- * PhoneConstants.PRESENTATION_xxx to calllog number presentation types
+ * TelecomManager.PRESENTATION_xxx to calllog number presentation types
* Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
* from any future radio changes.
* If the number field is empty set the presentation type to Unknown.
*/
private static int getLogNumberPresentation(String number, int presentation) {
- if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
+ if (presentation == TelecomManager.PRESENTATION_RESTRICTED) {
return presentation;
}
- if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
+ if (presentation == TelecomManager.PRESENTATION_PAYPHONE) {
return presentation;
}
if (TextUtils.isEmpty(number)
- || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
+ || presentation == TelecomManager.PRESENTATION_UNKNOWN) {
return PRESENTATION_UNKNOWN;
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 2af827e..a65c8fd 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -184,7 +184,8 @@
public static final int LISTEN_CELL_INFO = 0x00000400;
/**
- * Listen for {@link PreciseCallState.State} of ringing, background and foreground calls.
+ * Listen for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
+ * background and foreground calls.
*
* @hide
*/
diff --git a/telephony/java/android/telephony/Rlog.java b/core/java/android/telephony/Rlog.java
similarity index 100%
rename from telephony/java/android/telephony/Rlog.java
rename to core/java/android/telephony/Rlog.java
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 456789fb..5c42730 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -29,13 +29,13 @@
import android.os.HandlerExecutor;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.telephony.Annotation;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.CallState;
import android.telephony.Annotation.DataActivityType;
import android.telephony.Annotation.DataFailureCause;
import android.telephony.Annotation.DataState;
import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseCallStates;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
@@ -43,7 +43,6 @@
import android.telephony.CellInfo;
import android.telephony.DisconnectCause;
import android.telephony.PhoneCapability;
-import android.telephony.PreciseCallState.State;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -624,8 +623,10 @@
*
* @hide
*/
- public void notifyPreciseCallState(int subId, int slotIndex, @State int ringCallPreciseState,
- @State int foregroundCallPreciseState, @State int backgroundCallPreciseState) {
+ public void notifyPreciseCallState(int subId, int slotIndex,
+ @PreciseCallStates int ringCallPreciseState,
+ @PreciseCallStates int foregroundCallPreciseState,
+ @PreciseCallStates int backgroundCallPreciseState) {
try {
sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState,
foregroundCallPreciseState, backgroundCallPreciseState);
diff --git a/core/java/android/util/TimingLogger.java b/core/java/android/util/TimingLogger.java
index be442da..5a4a512 100644
--- a/core/java/android/util/TimingLogger.java
+++ b/core/java/android/util/TimingLogger.java
@@ -44,7 +44,14 @@
* D/TAG ( 3459): methodA: 6 ms, work C
* D/TAG ( 3459): methodA: end, 16 ms
* </pre>
+ *
+ * @deprecated Use {@link android.os.Trace}, or
+ * <a href="https://developer.android.com/studio/profile/benchmark">Android Studio</a>. In
+ * general, milliseconds is the wrong granularity for method-level tracing. Rounding errors
+ * can overemphasize cheap operations, or underemphasize repeated operations. This timing
+ * system also does not take CPU scheduling or frequency into account.
*/
+@Deprecated
public class TimingLogger {
/**
diff --git a/core/java/com/android/internal/app/DisableCarModeActivity.java b/core/java/com/android/internal/app/DisableCarModeActivity.java
index 7943c61..d44312b 100644
--- a/core/java/com/android/internal/app/DisableCarModeActivity.java
+++ b/core/java/com/android/internal/app/DisableCarModeActivity.java
@@ -33,7 +33,9 @@
try {
IUiModeManager uiModeManager = IUiModeManager.Stub.asInterface(
ServiceManager.getService("uimode"));
- uiModeManager.disableCarMode(UiModeManager.DISABLE_CAR_MODE_GO_HOME);
+ uiModeManager.disableCarModeByCallingPackage(UiModeManager.DISABLE_CAR_MODE_GO_HOME
+ | UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES,
+ getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Failed to disable car mode", e);
}
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index aef4dbf..e3d07aa 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -208,7 +208,7 @@
* @return the maximized Locale instance.
*/
public static Locale addLikelySubtags(Locale locale) {
- return libcore.icu.ICU.addLikelySubtags(locale);
+ return ULocale.addLikelySubtags(ULocale.forLocale(locale)).toLocale();
}
/**
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 045a680..7dcb12c 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -171,6 +171,15 @@
void clearOverrides(in String packageName);
/**
+ * Revert overrides to compatibility changes. Doesn't kill the app, to be only used in tests.
+ *
+ * @param packageName The package name of the app whose overrides will be cleared.
+ *
+ */
+ void clearOverridesForTest(in String packageName);
+
+
+ /**
* Get configs for an application.
*
* @param appInfo The application whose config will be returned.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 486d24c..7b61277 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -87,6 +87,7 @@
"android_text_Hyphenator.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
+ "android_os_HidlMemory.cpp",
"android_os_HidlSupport.cpp",
"android_os_HwBinder.cpp",
"android_os_HwBlob.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9e4c222..2383731 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -191,6 +191,7 @@
extern int register_android_os_Trace(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_UEventObserver(JNIEnv* env);
+extern int register_android_os_HidlMemory(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
extern int register_android_os_SharedMemory(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
@@ -1474,6 +1475,7 @@
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Parcel),
+ REG_JNI(register_android_os_HidlMemory),
REG_JNI(register_android_os_HidlSupport),
REG_JNI(register_android_os_HwBinder),
REG_JNI(register_android_os_HwBlob),
diff --git a/core/jni/android_os_HidlMemory.cpp b/core/jni/android_os_HidlMemory.cpp
new file mode 100644
index 0000000..69e4818
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "android_os_HidlMemory.h"
+#include "core_jni_helpers.h"
+#include "android_os_NativeHandle.h"
+
+#define PACKAGE_PATH "android/os"
+#define CLASS_NAME "HidlMemory"
+#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
+
+namespace android {
+
+namespace {
+
+static struct {
+ jclass clazz;
+ jfieldID nativeContext; // long
+ jmethodID constructor; // HidlMemory(String, long, NativeHandle)
+ jmethodID getName; // String HidlMemory.getName()
+ jmethodID getSize; // int HidlMemory.getSize()
+ jmethodID getHandle; // NativeHandle HidlMemory.getHandle()
+} gFields;
+
+std::string stringFromJava(JNIEnv* env, jstring jstr) {
+ ScopedUtfChars s(env, jstr);
+ return s.c_str();
+}
+
+jstring stringToJava(JNIEnv* env, const std::string& cstr) {
+ return env->NewStringUTF(cstr.c_str());
+}
+
+static void nativeFinalize(JNIEnv* env, jobject jobj) {
+ jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+ JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+ delete native;
+}
+
+static JNINativeMethod gMethods[] = {
+ {"nativeFinalize", "()V", (void*) nativeFinalize},
+};
+
+} // namespace
+
+JHidlMemory::~JHidlMemory() {
+ if (mObj) {
+ // Must manually delete the underlying handle - hidl_memory doesn't own
+ // it.
+ native_handle_delete(const_cast<native_handle_t*>(mObj->handle()));
+ }
+}
+
+/* static */ const hardware::hidl_memory* JHidlMemory::fromJava(JNIEnv* env,
+ jobject jobj) {
+ // Try to get the result from cache.
+ env->MonitorEnter(jobj);
+ JHidlMemory* obj = getNativeContext(env, jobj);
+ if (!obj->mObj) {
+ // Create and cache.
+ obj->mObj = javaToNative(env, jobj);
+ }
+ env->MonitorExit(jobj);
+ return obj->mObj.get();
+}
+
+/* static */ jobject JHidlMemory::toJava(JNIEnv* env,
+ const hardware::hidl_memory& cobj) {
+ if (cobj.size() > std::numeric_limits<jlong>::max()) {
+ return nullptr;
+ }
+ jstring jname = stringToJava(env, cobj.name());
+ jlong jsize = static_cast<jlong>(cobj.size());
+ jobject jhandle =
+ JNativeHandle::MakeJavaNativeHandleObj(env, cobj.handle());
+
+ // We're sharing the handle of cobj, so the Java instance doesn't own it.
+ return env->NewObject(gFields.clazz,
+ gFields.constructor,
+ jname,
+ jsize,
+ jhandle,
+ false);
+}
+
+/* static */ std::unique_ptr<hardware::hidl_memory> JHidlMemory::javaToNative(
+ JNIEnv* env,
+ jobject jobj) {
+ jstring jname =
+ static_cast<jstring>(env->CallObjectMethod(jobj, gFields.getName));
+ jlong jsize = env->CallLongMethod(jobj, gFields.getSize);
+ jobject jhandle = env->CallObjectMethod(jobj, gFields.getHandle);
+
+ if (jsize > std::numeric_limits<size_t>::max()) {
+ return nullptr;
+ }
+
+ std::string cname = stringFromJava(env, jname);
+ size_t csize = jsize;
+ // We created the handle here, we're responsible to call
+ // native_handle_delete() on it. However, we don't assume ownership of the
+ // underlying fd, so we shouldn't call native_handle_close() on it.
+ native_handle_t* chandle = JNativeHandle::MakeCppNativeHandle(env, jhandle,
+ nullptr);
+ // hidl_memory doesn't take ownership of the handle here, so won't delete
+ // or close it.
+ return std::make_unique<hardware::hidl_memory>(cname, chandle, csize);
+}
+
+/* static */ JHidlMemory* JHidlMemory::getNativeContext(JNIEnv* env,
+ jobject jobj) {
+ env->MonitorEnter(jobj);
+ jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+ JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+ if (!native) {
+ native = new JHidlMemory();
+ env->SetLongField(jobj,
+ gFields.nativeContext,
+ reinterpret_cast<jlong>(native));
+ }
+ env->MonitorExit(jobj);
+ return native;
+}
+
+int register_android_os_HidlMemory(JNIEnv* env) {
+ jclass clazz = FindClassOrDie(env, CLASS_PATH);
+ gFields.clazz = MakeGlobalRefOrDie(env, clazz);
+
+ gFields.nativeContext = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
+
+ gFields.constructor = GetMethodIDOrDie(env,
+ clazz,
+ "<init>",
+ "(Ljava/lang/String;JL" PACKAGE_PATH "/NativeHandle;)V");
+ gFields.getName =
+ GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
+ gFields.getSize = GetMethodIDOrDie(env, clazz, "getSize", "()J");
+ gFields.getHandle = GetMethodIDOrDie(env,
+ clazz,
+ "getHandle",
+ "()L" PACKAGE_PATH "/NativeHandle;");
+
+ RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
+
+ return 0;
+}
+
+} // namespace android
+
diff --git a/core/jni/android_os_HidlMemory.h b/core/jni/android_os_HidlMemory.h
new file mode 100644
index 0000000..993a132
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef ANDROID_OS_HIDL_MEMORY_H
+#define ANDROID_OS_HIDL_MEMORY_H
+
+#include <jni.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+
+// A utility class for handling the android.os.HidlMemory class from JNI code.
+class JHidlMemory final {
+ public:
+ // Convert an android.os.HidlMemory object to its C++ counterpart,
+ // hardware::hidl_memory.
+ // No duplication of file descriptors is performed.
+ // The returned reference is owned by the underlying Java object.
+ // Returns nullptr if conversion cannot be done.
+ static const hardware::hidl_memory* fromJava(JNIEnv* env,
+ jobject jobj);
+
+ // Convert a hardware::hidl_memory object to its Java counterpart,
+ // android.os.HidlMemory.
+ // No duplication of file descriptors is performed.
+ // Returns nullptr if conversion cannot be done.
+ static jobject toJava(JNIEnv* env,
+ const hardware::hidl_memory& cobj);
+
+ ~JHidlMemory();
+
+ private:
+ // We store an instance of type JHidlMemory attached to every Java object
+ // of type HidlMemory, for holding any native context we need. This instance
+ // will get deleted when finalize() is called on the Java object.
+ // This method either extracts the native object from the Java object, or
+ // attached a new one if it doesn't yet exist.
+ static JHidlMemory* getNativeContext(JNIEnv* env, jobject obj);
+
+ // Convert an android.os.HidlMemory object to its C++ counterpart,
+ // hardware::hidl_memory.
+ // No duplication of file descriptors is performed.
+ // IMPORTANT: caller is responsible to native_handle_delete() the handle of the
+ // returned object. This is due to an underlying limitation of the hidl_handle
+ // type, where ownership of the handle implies ownership of the fd and we don't
+ // want the latter.
+ // Returns nullptr if conversion cannot be done.
+ static std::unique_ptr<hardware::hidl_memory> javaToNative(JNIEnv* env,
+ jobject jobj);
+
+ std::unique_ptr<hardware::hidl_memory> mObj;
+};
+
+int register_android_os_HidlMemory(JNIEnv* env);
+
+} // namespace android
+
+#endif //ANDROID_OS_HIDL_MEMORY_H
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index e5b72ca..0fb2911 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -340,6 +340,14 @@
return env->NewStringUTF(s->c_str());
}
+static jlong JHwBlob_native_getFieldHandle(JNIEnv* env,
+ jobject thiz,
+ jlong offset) {
+ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+ return reinterpret_cast<jlong>(blob->data()) + offset;
+}
+
#define DEFINE_BLOB_ARRAY_COPIER(Suffix,Type,NewType) \
static void JHwBlob_native_copyTo ## Suffix ## Array( \
JNIEnv *env, \
@@ -593,6 +601,7 @@
{ "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
{ "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
{ "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
+ { "getFieldHandle", "(J)J", (void*) JHwBlob_native_getFieldHandle},
{ "copyToBoolArray", "(J[ZI)V", (void *)JHwBlob_native_copyToBoolArray },
{ "copyToInt8Array", "(J[BI)V", (void *)JHwBlob_native_copyToInt8Array },
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index f437a78..151dbfc 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -20,6 +20,7 @@
#include "android_os_HwParcel.h"
+#include "android_os_HidlMemory.h"
#include "android_os_HwBinder.h"
#include "android_os_HwBlob.h"
#include "android_os_NativeHandle.h"
@@ -27,6 +28,8 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/Status.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -650,6 +653,36 @@
signalExceptionForError(env, err);
}
+static void JHwParcel_native_writeHidlMemory(
+ JNIEnv *env, jobject thiz, jobject jmem) {
+
+ if (jmem == nullptr) {
+ jniThrowException(env, "java/lang/NullPointerException", nullptr);
+ return;
+ }
+
+ status_t err = OK;
+
+ // Convert the Java object to its C++ counterpart.
+ const hardware::hidl_memory* cmem = JHidlMemory::fromJava(env, jmem);
+ if (cmem == nullptr) {
+ err = BAD_VALUE;
+ }
+
+ if (err == OK) {
+ // Write it to the parcel.
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ size_t parentHandle;
+ err = parcel->writeBuffer(cmem, sizeof(*cmem), &parentHandle);
+ if (err == OK) {
+ err = hardware::writeEmbeddedToParcel(*cmem, parcel, parentHandle, 0);
+ }
+ }
+ signalExceptionForError(env, err);
+}
+
static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) {
String16 utf16String(s.c_str(), s.size());
@@ -877,6 +910,74 @@
return objArray;
}
+static status_t readEmbeddedHidlMemory(JNIEnv* env,
+ hardware::Parcel* parcel,
+ const hardware::hidl_memory& mem,
+ size_t parentHandle,
+ size_t parentOffset,
+ jobject* result) {
+ status_t err = hardware::readEmbeddedFromParcel(mem,
+ *parcel,
+ parentHandle,
+ parentOffset);
+ if (err == OK) {
+ // Convert to Java.
+ *result = JHidlMemory::toJava(env, mem);
+ if (*result == nullptr) {
+ err = BAD_VALUE;
+ }
+ }
+ return err;
+}
+
+static jobject JHwParcel_native_readHidlMemory(
+ JNIEnv* env, jobject thiz) {
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ jobject result = nullptr;
+
+ const hardware::hidl_memory* mem;
+ size_t parentHandle;
+
+ status_t err = parcel->readBuffer(sizeof(*mem),
+ &parentHandle,
+ reinterpret_cast<const void**>(&mem));
+ if (err == OK) {
+ err = readEmbeddedHidlMemory(env,
+ parcel,
+ *mem,
+ parentHandle,
+ 0,
+ &result);
+ }
+
+ signalExceptionForError(env, err);
+ return result;
+}
+
+static jobject JHwParcel_native_readEmbeddedHidlMemory(
+ JNIEnv* env,
+ jobject thiz,
+ jlong fieldHandle,
+ jlong parentHandle,
+ jlong offset) {
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ jobject result = nullptr;
+ const hardware::hidl_memory* mem =
+ reinterpret_cast<const hardware::hidl_memory*>(fieldHandle);
+ status_t err = readEmbeddedHidlMemory(env,
+ parcel,
+ *mem,
+ parentHandle,
+ offset,
+ &result);
+ signalExceptionForError(env, err);
+ return result;
+}
+
static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
@@ -1075,6 +1176,14 @@
{ "release", "()V",
(void *)JHwParcel_native_release },
+ {"writeHidlMemory", "(L" PACKAGE_PATH "/HidlMemory;)V",
+ (void*) JHwParcel_native_writeHidlMemory},
+
+ {"readHidlMemory", "()L" PACKAGE_PATH "/HidlMemory;",
+ (void*) JHwParcel_native_readHidlMemory},
+
+ {"readEmbeddedHidlMemory", "(JJJ)L" PACKAGE_PATH "/HidlMemory;",
+ (void*) JHwParcel_native_readEmbeddedHidlMemory},
};
namespace android {
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 87f498a..7f3b32e 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -17,9 +17,13 @@
#define LOG_TAG "SysPropJNI"
+#include <utility>
+#include <optional>
+
#include "android-base/logging.h"
+#include "android-base/parsebool.h"
+#include "android-base/parseint.h"
#include "android-base/properties.h"
-#include "cutils/properties.h"
#include "utils/misc.h"
#include <utils/Log.h>
#include "jni.h"
@@ -28,86 +32,171 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
-namespace android
-{
+#if defined(__BIONIC__)
+# include <sys/system_properties.h>
+#else
+struct prop_info;
+#endif
+namespace android {
namespace {
-template <typename T, typename Handler>
-T ConvertKeyAndForward(JNIEnv *env, jstring keyJ, T defJ, Handler handler) {
- std::string key;
- {
- // Scope the String access. If the handler can throw an exception,
- // releasing the string characters late would trigger an abort.
- ScopedUtfChars key_utf(env, keyJ);
- if (key_utf.c_str() == nullptr) {
- return defJ;
- }
- key = key_utf.c_str(); // This will make a copy, but we can't avoid
- // with the existing interface in
- // android::base.
- }
- return handler(key, defJ);
+using android::base::ParseBoolResult;
+
+template<typename Functor>
+void ReadProperty(const prop_info* prop, Functor&& functor)
+{
+#if defined(__BIONIC__)
+ auto thunk = [](void* cookie,
+ const char* /*name*/,
+ const char* value,
+ uint32_t /*serial*/) {
+ std::forward<Functor>(*static_cast<Functor*>(cookie))(value);
+ };
+ __system_property_read_callback(prop, thunk, &functor);
+#else
+ LOG(FATAL) << "fast property access supported only on device";
+#endif
}
-jstring SystemProperties_getSS(JNIEnv *env, jclass clazz, jstring keyJ,
+template<typename Functor>
+void ReadProperty(JNIEnv* env, jstring keyJ, Functor&& functor)
+{
+ ScopedUtfChars key(env, keyJ);
+ if (!key.c_str()) {
+ return;
+ }
+#if defined(__BIONIC__)
+ const prop_info* prop = __system_property_find(key.c_str());
+ if (!prop) {
+ return;
+ }
+ ReadProperty(prop, std::forward<Functor>(functor));
+#else
+ std::forward<Functor>(functor)(
+ android::base::GetProperty(key.c_str(), "").c_str());
+#endif
+}
+
+jstring SystemProperties_getSS(JNIEnv* env, jclass clazz, jstring keyJ,
jstring defJ)
{
- // Using ConvertKeyAndForward is sub-optimal for copying the key string,
- // but improves reuse and reasoning over code.
- auto handler = [&](const std::string& key, jstring defJ) {
- std::string prop_val = android::base::GetProperty(key, "");
- if (!prop_val.empty()) {
- return env->NewStringUTF(prop_val.c_str());
- };
- if (defJ != nullptr) {
- return defJ;
+ jstring ret = defJ;
+ ReadProperty(env, keyJ, [&](const char* value) {
+ if (value[0]) {
+ ret = env->NewStringUTF(value);
}
- // This function is specified to never return null (or have an
- // exception pending).
- return env->NewStringUTF("");
- };
- return ConvertKeyAndForward(env, keyJ, defJ, handler);
-}
-
-jstring SystemProperties_getS(JNIEnv *env, jclass clazz, jstring keyJ)
-{
- return SystemProperties_getSS(env, clazz, keyJ, nullptr);
+ });
+ if (ret == nullptr && !env->ExceptionCheck()) {
+ ret = env->NewStringUTF(""); // Legacy behavior
+ }
+ return ret;
}
template <typename T>
T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ,
T defJ)
{
- auto handler = [](const std::string& key, T defV) {
- return android::base::GetIntProperty<T>(key, defV);
- };
- return ConvertKeyAndForward(env, keyJ, defJ, handler);
+ T ret = defJ;
+ ReadProperty(env, keyJ, [&](const char* value) {
+ android::base::ParseInt<T>(value, &ret);
+ });
+ return ret;
+}
+
+static jboolean jbooleanFromParseBoolResult(ParseBoolResult parseResult, jboolean defJ) {
+ jboolean ret;
+ switch (parseResult) {
+ case ParseBoolResult::kError:
+ ret = defJ;
+ break;
+ case ParseBoolResult::kFalse:
+ ret = JNI_FALSE;
+ break;
+ case ParseBoolResult::kTrue:
+ ret = JNI_TRUE;
+ break;
+ }
+ return ret;
}
jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ,
jboolean defJ)
{
- auto handler = [](const std::string& key, jboolean defV) -> jboolean {
- bool result = android::base::GetBoolProperty(key, defV);
- return result ? JNI_TRUE : JNI_FALSE;
- };
- return ConvertKeyAndForward(env, keyJ, defJ, handler);
+ ParseBoolResult parseResult = ParseBoolResult::kError;
+ ReadProperty(env, keyJ, [&](const char* value) {
+ parseResult = android::base::ParseBool(value);
+ });
+ return jbooleanFromParseBoolResult(parseResult, defJ);
+}
+
+jlong SystemProperties_find(JNIEnv* env, jclass, jstring keyJ)
+{
+#if defined(__BIONIC__)
+ ScopedUtfChars key(env, keyJ);
+ if (!key.c_str()) {
+ return 0;
+ }
+ const prop_info* prop = __system_property_find(key.c_str());
+ return reinterpret_cast<jlong>(prop);
+#else
+ LOG(FATAL) << "fast property access supported only on device";
+ __builtin_unreachable(); // Silence warning
+#endif
+}
+
+jstring SystemProperties_getH(JNIEnv* env, jclass clazz, jlong propJ)
+{
+ jstring ret;
+ auto prop = reinterpret_cast<const prop_info*>(propJ);
+ ReadProperty(prop, [&](const char* value) {
+ ret = env->NewStringUTF(value);
+ });
+ return ret;
+}
+
+template <typename T>
+T SystemProperties_get_integralH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, T defJ)
+{
+ T ret = defJ;
+ auto prop = reinterpret_cast<const prop_info*>(propJ);
+ ReadProperty(prop, [&](const char* value) {
+ android::base::ParseInt<T>(value, &ret);
+ });
+ return ret;
+}
+
+jboolean SystemProperties_get_booleanH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, jboolean defJ)
+{
+ ParseBoolResult parseResult = ParseBoolResult::kError;
+ auto prop = reinterpret_cast<const prop_info*>(propJ);
+ ReadProperty(prop, [&](const char* value) {
+ parseResult = android::base::ParseBool(value);
+ });
+ return jbooleanFromParseBoolResult(parseResult, defJ);
}
void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
jstring valJ)
{
- auto handler = [&](const std::string& key, bool) {
- std::string val;
- if (valJ != nullptr) {
- ScopedUtfChars key_utf(env, valJ);
- val = key_utf.c_str();
+ ScopedUtfChars key(env, keyJ);
+ if (!key.c_str()) {
+ return;
+ }
+ std::optional<ScopedUtfChars> value;
+ if (valJ != nullptr) {
+ value.emplace(env, valJ);
+ if (!value->c_str()) {
+ return;
}
- return android::base::SetProperty(key, val);
- };
- if (!ConvertKeyAndForward(env, keyJ, true, handler)) {
- // Must have been a failure in SetProperty.
+ }
+ bool success;
+#if defined(__BIONIC__)
+ success = !__system_property_set(key.c_str(), value ? value->c_str() : "");
+#else
+ success = android::base::SetProperty(key.c_str(), value ? value->c_str() : "");
+#endif
+ if (!success) {
jniThrowException(env, "java/lang/RuntimeException",
"failed to set system property (check logcat for reason)");
}
@@ -157,8 +246,6 @@
int register_android_os_SystemProperties(JNIEnv *env)
{
const JNINativeMethod method_table[] = {
- { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
- (void*) SystemProperties_getS },
{ "native_get",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) SystemProperties_getSS },
@@ -168,6 +255,18 @@
(void*) SystemProperties_get_integral<jlong> },
{ "native_get_boolean", "(Ljava/lang/String;Z)Z",
(void*) SystemProperties_get_boolean },
+ { "native_find",
+ "(Ljava/lang/String;)J",
+ (void*) SystemProperties_find },
+ { "native_get",
+ "(J)Ljava/lang/String;",
+ (void*) SystemProperties_getH },
+ { "native_get_int", "(JI)I",
+ (void*) SystemProperties_get_integralH<jint> },
+ { "native_get_long", "(JJ)J",
+ (void*) SystemProperties_get_integralH<jlong> },
+ { "native_get_boolean", "(JZ)Z",
+ (void*) SystemProperties_get_booleanH },
{ "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) SystemProperties_set },
{ "native_add_change_callback", "()V",
@@ -179,4 +278,4 @@
method_table, NELEM(method_table));
}
-};
+} // namespace android
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 3704ccd..8fabb23 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -34,6 +34,7 @@
// Static whitelist of open paths that the zygote is allowed to keep open.
static const char* kPathWhitelist[] = {
"/apex/com.android.conscrypt/javalib/conscrypt.jar",
+ "/apex/com.android.ipsec/javalib/ike.jar",
"/apex/com.android.media/javalib/updatable-media.jar",
"/dev/null",
"/dev/socket/zygote",
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index c023438..6bf4c43 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2401,4 +2401,11 @@
// OS: Q
// Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
+
+ // ---- End Q Constants, all Q constants go above this line ----
+
+ // OPEN: Settings > Developer Options > Platform Compat
+ // CATEGORY: SETTINGS
+ // OS: R
+ SETTINGS_PLATFORM_COMPAT_DASHBOARD = 1805;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 74b4f34..216b87f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -108,6 +108,8 @@
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
+ <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIVILEGED" />
+ <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIVILEGED" />
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
<protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
@@ -4339,6 +4341,21 @@
it will be ignored.
@hide -->
<permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows entering or exiting car mode using a specified priority.
+ This permission is required to use UiModeManager while specifying a priority for the calling
+ app. A device manufacturer uses this permission to prioritize the apps which can
+ potentially request to enter car-mode on a device to help establish the correct behavior
+ where multiple such apps are active at the same time.
+ @hide -->
+ <permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Required to receive ACTION_ENTER_CAR_MODE_PRIVILEGED or
+ ACTION_EXIT_CAR_MODE_PRIVILEGED.
+ @hide -->
+ <permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"
android:protectionLevel="signature|privileged" />
<!-- The system process is explicitly the only one allowed to launch the
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 84d4857..4b4baa9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -529,7 +529,7 @@
- TYPE_ETHERNET (9) is prepended to this list, and
- - the return value of TelephonyManager.isTetherApnRequired()
+ - the return value of TelephonyManager.isTetheringApnRequired()
determines how the array is further modified:
* TRUE (DUN REQUIRED).
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index 0f1c71d..c6c0b46 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -22,7 +22,7 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiSsid;
+import android.net.wifi.WifiManager;
import androidx.test.runner.AndroidJUnit4;
@@ -65,7 +65,7 @@
@Test
public void createFromWifi_noneSsid() throws Exception {
- when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
+ when(mWifiInfo.getSSID()).thenReturn(WifiManager.UNKNOWN_SSID);
when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
}
@@ -106,7 +106,7 @@
}
@Test
- public void createFromScanResult_nullWifiSsid() {
+ public void createFromScanResult_nullSsid() {
ScanResult scanResult = new ScanResult();
scanResult.BSSID = VALID_BSSID;
@@ -114,18 +114,18 @@
}
@Test
- public void createFromScanResult_emptyWifiSsid() {
+ public void createFromScanResult_emptySsid() {
ScanResult scanResult = new ScanResult();
- scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded("");
+ scanResult.SSID = "";
scanResult.BSSID = VALID_BSSID;
assertNull(NetworkKey.createFromScanResult(scanResult));
}
@Test
- public void createFromScanResult_noneWifiSsid() {
+ public void createFromScanResult_noneSsid() {
ScanResult scanResult = new ScanResult();
- scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(WifiSsid.NONE);
+ scanResult.SSID = WifiManager.UNKNOWN_SSID;
scanResult.BSSID = VALID_BSSID;
assertNull(NetworkKey.createFromScanResult(scanResult));
@@ -134,7 +134,7 @@
@Test
public void createFromScanResult_nullBssid() {
ScanResult scanResult = new ScanResult();
- scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+ scanResult.SSID = VALID_UNQUOTED_SSID;
assertNull(NetworkKey.createFromScanResult(scanResult));
}
@@ -142,7 +142,7 @@
@Test
public void createFromScanResult_emptyBssid() {
ScanResult scanResult = new ScanResult();
- scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+ scanResult.SSID = VALID_UNQUOTED_SSID;
scanResult.BSSID = "";
assertNull(NetworkKey.createFromScanResult(scanResult));
@@ -151,16 +151,16 @@
@Test
public void createFromScanResult_invalidBssid() {
ScanResult scanResult = new ScanResult();
- scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+ scanResult.SSID = VALID_UNQUOTED_SSID;
scanResult.BSSID = INVALID_BSSID;
assertNull(NetworkKey.createFromScanResult(scanResult));
}
@Test
- public void createFromScanResult_validWifiSsid() {
+ public void createFromScanResult_validSsid() {
ScanResult scanResult = new ScanResult();
- scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+ scanResult.SSID = VALID_UNQUOTED_SSID;
scanResult.BSSID = VALID_BSSID;
NetworkKey expected = new NetworkKey(new WifiKey(VALID_SSID, VALID_BSSID));
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 928351e..b48ac33 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -93,6 +93,27 @@
}
@SmallTest
+ private static void testHandle() throws Exception {
+ String value;
+ SystemProperties.Handle handle = SystemProperties.find("doesnotexist_2341431");
+ assertNull(handle);
+ SystemProperties.set(KEY, "abc");
+ handle = SystemProperties.find(KEY);
+ assertNotNull(handle);
+ value = handle.get();
+ assertEquals("abc", value);
+ SystemProperties.set(KEY, "blarg");
+ value = handle.get();
+ assertEquals("blarg", value);
+ SystemProperties.set(KEY, "1");
+ assertEquals(1, handle.getInt(-1));
+ assertEquals(1, handle.getLong(-1));
+ assertEquals(true, handle.getBoolean(false));
+ SystemProperties.set(KEY, "");
+ assertEquals(12345, handle.getInt(12345));
+ }
+
+ @SmallTest
public void testIntegralProperties() throws Exception {
testInt("", 123, 123);
testInt("", 0, 0);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 80f3cc6..9064abf 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -238,6 +238,7 @@
<permission name="android.permission.BIND_CONNECTION_SERVICE"/>
<permission name="android.permission.BIND_INCALL_SERVICE"/>
<permission name="android.permission.CALL_PRIVILEGED"/>
+ <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MANAGE_ROLE_HOLDERS"/>
@@ -328,6 +329,8 @@
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
<!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
<permission name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"/>
+ <!-- Permission required for UiModeManager cts test. -->
+ <permission name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 646aa13..c0a0422 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -348,16 +348,6 @@
return list(prefix, UID_SELF);
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public boolean reset() {
- try {
- return mBinder.reset() == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
/**
* Attempt to lock the keystore for {@code user}.
*
@@ -922,15 +912,26 @@
}
}
- public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
- byte[] entropy) {
+ /**
+ * Android KeyStore finish operation.
+ *
+ * @param token Authentication token.
+ * @param arguments Keymaster arguments
+ * @param input Optional additional input data.
+ * @param signature Optional signature to be verified.
+ * @param entropy Optional additional entropy
+ * @return OperationResult that will indicate success or error of the operation.
+ */
+ public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
+ byte[] signature, byte[] entropy) {
OperationPromise promise = new OperationPromise();
try {
mBinder.asBinder().linkToDeath(promise, 0);
arguments = arguments != null ? arguments : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
+ input = input != null ? input : new byte[0];
signature = signature != null ? signature : new byte[0];
- int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
+ int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
if (errorCode == NO_ERROR) {
return promise.getFuture().get();
} else {
@@ -948,7 +949,7 @@
}
public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
- return finish(token, arguments, signature, null);
+ return finish(token, arguments, null, signature, null);
}
private class KeystoreResultPromise
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index 441ee66..c6515ef 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -432,7 +432,7 @@
}
@Override
- public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
+ public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
throw new ProviderException("AAD stream does not support additional entropy");
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 3dc884e..17aacb9 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -210,13 +210,9 @@
}
}
if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- if (mKeySizeBits < 64) {
+ if (mKeySizeBits < 64 || mKeySizeBits > 512) {
throw new InvalidAlgorithmParameterException(
- "HMAC key size must be at least 64 bits.");
- }
- if (mKeySizeBits > 512 && spec.isStrongBoxBacked()) {
- throw new InvalidAlgorithmParameterException(
- "StrongBox HMAC key size must be smaller than 512 bits.");
+ "HMAC key sizes must be within 64-512 bits, inclusive.");
}
// JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
index e030478..75bea26 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
@@ -62,7 +62,7 @@
* Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
* be reached.
*/
- OperationResult finish(byte[] siganture, byte[] additionalEntropy);
+ OperationResult finish(byte[] input, byte[] siganture, byte[] additionalEntropy);
}
// Binder buffer is about 1MB, but it's shared between all active transactions of the process.
@@ -217,7 +217,8 @@
byte[] output = update(input, inputOffset, inputLength);
output = ArrayUtils.concat(output, flush());
- OperationResult opResult = mKeyStoreStream.finish(signature, additionalEntropy);
+ OperationResult opResult = mKeyStoreStream.finish(EmptyArray.BYTE, signature,
+ additionalEntropy);
if (opResult == null) {
throw new KeyStoreConnectException();
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
@@ -334,8 +335,8 @@
}
@Override
- public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
- return mKeyStore.finish(mOperationToken, null, signature, additionalEntropy);
+ public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
+ return mKeyStore.finish(mOperationToken, null, input, signature, additionalEntropy);
}
}
}
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 8c38d88..84a0e0d 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -26,7 +26,6 @@
#include <nativehelper/JNIHelp.h>
#include <binder/MemoryDealer.h>
-#include <drm/drm_framework_common.h>
#include <media/stagefright/foundation/ADebug.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -160,8 +159,4 @@
return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid());
}
-sp<DecryptHandle> JMediaDataSource::DrmInitialization(const char * /* mime */) {
- return NULL;
-}
-
} // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 39405d2..378baf4 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -47,7 +47,6 @@
virtual void close();
virtual uint32_t getFlags();
virtual String8 toString();
- virtual sp<DecryptHandle> DrmInitialization(const char *mime);
private:
// Protect all member variables with mLock because this object will be
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
index 5d84d64..1928ad9 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
@@ -21,7 +21,6 @@
import android.content.Intent;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.test.InstrumentationTestCase;
@@ -90,12 +89,10 @@
Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
- Rlog.d(TAG, "OnReceive redirection intent");
mReceiver.onReceive(mContext, intent);
mContext.waitForMs(100);
- Rlog.d(TAG, "verify carrier action: showPortalNotification");
verify(mNotificationMgr, times(1)).notify(mString.capture(), mInt.capture(),
mNotification.capture());
assertEquals(PORTAL_NOTIFICATION_ID, (int) mInt.getValue());
@@ -103,7 +100,6 @@
PendingIntent pendingIntent = mNotification.getValue().contentIntent;
assertNotNull(pendingIntent);
- Rlog.d(TAG, "verify carrier action: disable all metered apns");
verify(mTelephonyMgr).setCarrierDataEnabled(eq(false));
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 047ac59..13fc881 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -207,6 +207,9 @@
<!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+ <!-- Permission requried for CTS test - UiModeManagerTest -->
+ <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index f73ca1c..236f17e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -110,8 +110,7 @@
mCallbacks.add(callback);
if (mWifiManager != null) {
if (mCallbacks.size() == 1) {
- mWifiManager.registerSoftApCallback(this,
- new HandlerExecutor(mMainHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mMainHandler), this);
} else {
// mWifiManager#registerSoftApCallback triggers a call to
// onConnectedClientsChanged on the Main Handler. In order to always update
@@ -120,6 +119,7 @@
mMainHandler.post(() ->
callback.onHotspotChanged(isHotspotEnabled(),
mNumConnectedDevices));
+
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 7496e3a..631c580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -70,11 +70,11 @@
mContext.addMockSystemService(WifiManager.class, mWifiManager);
doAnswer((InvocationOnMock invocation) -> {
- ((WifiManager.SoftApCallback) invocation.getArgument(0))
+ ((WifiManager.SoftApCallback) invocation.getArgument(1))
.onConnectedClientsChanged(new ArrayList<>());
return null;
- }).when(mWifiManager).registerSoftApCallback(any(WifiManager.SoftApCallback.class),
- any(Executor.class));
+ }).when(mWifiManager).registerSoftApCallback(any(Executor.class),
+ any(WifiManager.SoftApCallback.class));
mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper()));
}
@@ -84,7 +84,7 @@
mController.addCallback(mCallback1);
mController.addCallback(mCallback2);
- verify(mWifiManager, times(1)).registerSoftApCallback(eq(mController), any());
+ verify(mWifiManager, times(1)).registerSoftApCallback(any(), eq(mController));
}
@Test
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 61bfb92..7b35f4d 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -20,12 +20,14 @@
srcs: [
"src/**/*.java",
":framework-tethering-shared-srcs",
+ ":net-module-utils-srcs",
":services-tethering-shared-srcs",
":servicescore-tethering-src",
],
static_libs: [
"androidx.annotation_annotation",
"netd_aidl_interface-java",
+ "netlink-client",
"networkstack-aidl-interfaces-java",
"android.hardware.tetheroffload.control-V1.0-java",
"tethering-client",
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index cf0e3b2..ca9b168 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -251,7 +251,7 @@
/** Check whether dun is required. */
public static boolean checkDunRequired(Context ctx, int id) {
final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
- return (tm != null) ? tm.isTetherApnRequired(id) : false;
+ return (tm != null) ? tm.isTetheringApnRequired(id) : false;
}
private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 9c65c0d..30bff35 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -145,7 +145,7 @@
@Test
public void testDunFromTelephonyManagerMeansDun() {
- when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(true);
+ when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(true);
final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -169,7 +169,7 @@
@Test
public void testDunNotRequiredFromTelephonyManagerMeansNoDun() {
- when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+ when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -212,7 +212,7 @@
@Test
public void testNoDefinedUpstreamTypesAddsEthernet() {
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{});
- when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+ when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -235,7 +235,7 @@
public void testDefinedUpstreamTypesSansEthernetAddsEthernet() {
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(
new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI});
- when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+ when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -253,7 +253,7 @@
public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() {
when(mResources.getIntArray(config_tether_upstream_types))
.thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI});
- when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+ when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a05c2cc..084a747 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -32,6 +32,7 @@
"android.hardware.power-V1.0-java",
"android.hardware.tv.cec-V1.0-java",
"app-compat-annotations",
+ "vintf-vibrator-java",
],
required: [
@@ -50,7 +51,6 @@
"android.hardware.biometrics.fingerprint-V2.1-java",
"android.hardware.oemlock-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
- "android.hardware.vibrator-V1.4-java",
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hidl.manager-V1.2-java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 81eb4b3..ce4cdc8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -146,6 +146,7 @@
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Log;
@@ -2185,6 +2186,11 @@
*/
@VisibleForTesting
public void systemReady() {
+ // Let PermissionMonitor#startMonitoring() running in the beginning of the systemReady
+ // before MultipathPolicyTracker.start(). Since mApps in PermissionMonitor needs to be
+ // populated first to ensure that listening network request which is sent by
+ // MultipathPolicyTracker won't be added NET_CAPABILITY_FOREGROUND capability.
+ mPermissionMonitor.startMonitoring();
mProxyTracker.loadGlobalProxy();
registerNetdEventCallback();
mTethering.systemReady();
@@ -2205,8 +2211,6 @@
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
-
- mPermissionMonitor.startMonitoring();
}
/**
@@ -3050,7 +3054,8 @@
}
private void handleAsyncChannelHalfConnect(Message msg) {
- AsyncChannel ac = (AsyncChannel) msg.obj;
+ ensureRunningOnConnectivityServiceThread();
+ final AsyncChannel ac = (AsyncChannel) msg.obj;
if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected");
@@ -3060,7 +3065,8 @@
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.isListen()) continue;
- NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
+ ensureRunningOnConnectivityServiceThread();
+ NetworkAgentInfo nai = nri.mSatisfier;
final int score;
final int serial;
if (nai != null) {
@@ -3116,6 +3122,7 @@
// ConnectivityService, free its interfaces and clean up.
// Must be called on the Handler thread.
private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
+ ensureRunningOnConnectivityServiceThread();
if (DBG) {
log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
}
@@ -3162,14 +3169,17 @@
// Remove all previously satisfied requests.
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest request = nai.requestAt(i);
- NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
+ final NetworkRequestInfo nri = mNetworkRequests.get(request);
+ ensureRunningOnConnectivityServiceThread();
+ final NetworkAgentInfo currentNetwork = nri.mSatisfier;
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
- clearNetworkForRequest(request.requestId);
+ nri.mSatisfier = null;
sendUpdatedScoreToFactories(request, null);
}
}
nai.clearLingerState();
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
+ mDefaultNetworkNai = null;
updateDataActivityTracking(null /* newNetwork */, nai);
notifyLockdownVpn(nai);
ensureNetworkTransitionWakelock(nai.name());
@@ -3178,7 +3188,7 @@
if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
updateAllVpnsCapabilities();
}
- rematchAllNetworksAndRequests(null, 0);
+ rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
if (nai.created) {
// Tell netd to clean up the configuration for this network
@@ -3253,6 +3263,7 @@
}
private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
+ ensureRunningOnConnectivityServiceThread();
mNetworkRequests.put(nri.request, nri);
mNetworkRequestInfoLogs.log("REGISTER " + nri);
if (nri.request.isListen()) {
@@ -3263,8 +3274,8 @@
}
}
}
- rematchAllNetworksAndRequests(null, 0);
- if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
+ rematchAllNetworksAndRequests();
+ if (nri.request.isRequest() && nri.mSatisfier == null) {
sendUpdatedScoreToFactories(nri.request, null);
}
}
@@ -3286,6 +3297,7 @@
// - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
// then it should be lingered.
private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
+ ensureRunningOnConnectivityServiceThread();
final int numRequests;
switch (reason) {
case TEARDOWN:
@@ -3310,6 +3322,7 @@
// If this Network is already the highest scoring Network for a request, or if
// there is hope for it to become one if it validated, then it is needed.
+ ensureRunningOnConnectivityServiceThread();
if (nri.request.isRequest() && nai.satisfies(nri.request) &&
(nai.isSatisfyingRequest(nri.request.requestId) ||
// Note that this catches two important cases:
@@ -3319,8 +3332,8 @@
// 2. Unvalidated WiFi will not be reaped when validated cellular
// is currently satisfying the request. This is desirable when
// WiFi ends up validating and out scoring cellular.
- getNetworkForRequest(nri.request.requestId).getCurrentScore() <
- nai.getCurrentScoreAsValidated())) {
+ nri.mSatisfier.getCurrentScore()
+ < nai.getCurrentScoreAsValidated())) {
return false;
}
}
@@ -3344,10 +3357,12 @@
}
private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
+ ensureRunningOnConnectivityServiceThread();
if (mNetworkRequests.get(nri.request) == null) {
return;
}
- if (getNetworkForRequest(nri.request.requestId) != null) {
+ ensureRunningOnConnectivityServiceThread();
+ if (nri.mSatisfier != null) {
return;
}
if (VDBG || (DBG && nri.request.isRequest())) {
@@ -3374,6 +3389,8 @@
}
private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
+ ensureRunningOnConnectivityServiceThread();
+
nri.unlinkDeathRecipient();
mNetworkRequests.remove(nri.request);
@@ -3393,7 +3410,8 @@
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
boolean wasKept = false;
- NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
+ ensureRunningOnConnectivityServiceThread();
+ final NetworkAgentInfo nai = nri.mSatisfier;
if (nai != null) {
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
nai.removeRequest(nri.request.requestId);
@@ -3410,7 +3428,7 @@
} else {
wasKept = true;
}
- clearNetworkForRequest(nri.request.requestId);
+ nri.mSatisfier = null;
if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
// Went from foreground to background.
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -3499,13 +3517,12 @@
}
if (accept != nai.networkMisc.acceptUnvalidated) {
- int oldScore = nai.getCurrentScore();
nai.networkMisc.acceptUnvalidated = accept;
// If network becomes partial connectivity and user already accepted to use this
// network, we should respect the user's option and don't need to popup the
// PARTIAL_CONNECTIVITY notification to user again.
nai.networkMisc.acceptPartialConnectivity = accept;
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
@@ -3574,9 +3591,8 @@
return;
}
if (!nai.avoidUnvalidated) {
- int oldScore = nai.getCurrentScore();
nai.avoidUnvalidated = true;
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
}
@@ -3677,7 +3693,7 @@
private void rematchForAvoidBadWifiUpdate() {
- rematchAllNetworksAndRequests(null, 0);
+ rematchAllNetworksAndRequests();
for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
sendUpdatedScoreToFactories(nai);
@@ -5093,6 +5109,11 @@
*/
private class NetworkRequestInfo implements IBinder.DeathRecipient {
final NetworkRequest request;
+ // The network currently satisfying this request, or null if none. Must only be touched
+ // on the handler thread. This only makes sense for network requests and not for listens,
+ // as defined by NetworkRequest#isRequest(). For listens, this is always null.
+ @Nullable
+ NetworkAgentInfo mSatisfier;
final PendingIntent mPendingIntent;
boolean mPendingIntentSent;
private final IBinder mBinder;
@@ -5479,16 +5500,6 @@
if (DBG) log("unregisterNetworkFactory for " + nfi.name);
}
- /**
- * NetworkAgentInfo supporting a request by requestId.
- * These have already been vetted (their Capabilities satisfy the request)
- * and the are the highest scored network available.
- * the are keyed off the Requests requestId.
- */
- // NOTE: Accessed on multiple threads, must be synchronized on itself.
- @GuardedBy("mNetworkForRequestId")
- private final SparseArray<NetworkAgentInfo> mNetworkForRequestId = new SparseArray<>();
-
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForNetId")
private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
@@ -5506,7 +5517,11 @@
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
// Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
+ @NonNull
private final NetworkRequest mDefaultRequest;
+ // The NetworkAgentInfo currently satisfying the default request, if any.
+ @Nullable
+ private volatile NetworkAgentInfo mDefaultNetworkNai = null;
// Request used to optionally keep mobile data active even when higher
// priority networks like Wi-Fi are active.
@@ -5516,26 +5531,8 @@
// priority networks like ethernet are active.
private final NetworkRequest mDefaultWifiRequest;
- private NetworkAgentInfo getNetworkForRequest(int requestId) {
- synchronized (mNetworkForRequestId) {
- return mNetworkForRequestId.get(requestId);
- }
- }
-
- private void clearNetworkForRequest(int requestId) {
- synchronized (mNetworkForRequestId) {
- mNetworkForRequestId.remove(requestId);
- }
- }
-
- private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) {
- synchronized (mNetworkForRequestId) {
- mNetworkForRequestId.put(requestId, nai);
- }
- }
-
private NetworkAgentInfo getDefaultNetwork() {
- return getNetworkForRequest(mDefaultRequest.requestId);
+ return mDefaultNetworkNai;
}
@Nullable
@@ -5968,7 +5965,7 @@
} else {
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests();
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
@@ -6253,7 +6250,7 @@
}
}
- private void makeDefault(NetworkAgentInfo newNetwork) {
+ private void makeDefault(@NonNull final NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
try {
@@ -6262,6 +6259,7 @@
loge("Exception setting default network :" + e);
}
+ mDefaultNetworkNai = newNetwork;
notifyLockdownVpn(newNetwork);
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
@@ -6296,6 +6294,41 @@
}
}
+ private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
+ @NonNull final NetworkAgentInfo newNetwork) {
+ final int score = newNetwork.getCurrentScore();
+ final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = new ArrayMap<>();
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ // Process requests in the first pass and listens in the second pass. This allows us to
+ // change a network's capabilities depending on which requests it has. This is only
+ // correct if the change in capabilities doesn't affect whether the network satisfies
+ // requests or not, and doesn't affect the network's score.
+ if (nri.request.isListen()) continue;
+
+ final NetworkAgentInfo currentNetwork = nri.mSatisfier;
+ final boolean satisfies = newNetwork.satisfies(nri.request);
+ if (newNetwork == currentNetwork && satisfies) continue;
+
+ // check if it satisfies the NetworkCapabilities
+ if (VDBG) log(" checking if request is satisfied: " + nri.request);
+ if (satisfies) {
+ // next check if it's better than any current network we're using for
+ // this request
+ if (VDBG || DDBG) {
+ log("currentScore = "
+ + (currentNetwork != null ? currentNetwork.getCurrentScore() : 0)
+ + ", newScore = " + score);
+ }
+ if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
+ reassignedRequests.put(nri, newNetwork);
+ }
+ } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
+ reassignedRequests.put(nri, null);
+ }
+ }
+ return reassignedRequests;
+ }
+
// Handles a network appearing or improving its score.
//
// - Evaluates all current NetworkRequests that can be
@@ -6309,10 +6342,6 @@
// - Tears down newNetwork if it just became validated
// but turns out to be unneeded.
//
- // - If reapUnvalidatedNetworks==REAP, tears down unvalidated
- // networks that have no chance (i.e. even if validated)
- // of becoming the highest scoring network.
- //
// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
// it does not remove NetworkRequests that other Networks could better satisfy.
// If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
@@ -6320,11 +6349,9 @@
// as it performs better by a factor of the number of Networks.
//
// @param newNetwork is the network to be matched against NetworkRequests.
- // @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be
- // performed to tear down unvalidated networks that have no chance (i.e. even if
- // validated) of becoming the highest scoring network.
- private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork,
- ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now) {
+ // @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime();
+ private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) {
+ ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
boolean keep = newNetwork.isVPN();
boolean isNewDefault = false;
@@ -6335,74 +6362,54 @@
if (VDBG || DDBG) log("rematching " + newNetwork.name());
- // Find and migrate to this Network any NetworkRequests for
- // which this network is now the best.
- ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<>();
- ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
+ final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
+ computeRequestReassignmentForNetwork(newNetwork);
+
NetworkCapabilities nc = newNetwork.networkCapabilities;
if (VDBG) log(" network has: " + nc);
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- // Process requests in the first pass and listens in the second pass. This allows us to
- // change a network's capabilities depending on which requests it has. This is only
- // correct if the change in capabilities doesn't affect whether the network satisfies
- // requests or not, and doesn't affect the network's score.
- if (nri.request.isListen()) continue;
- final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);
- final boolean satisfies = newNetwork.satisfies(nri.request);
- if (newNetwork == currentNetwork && satisfies) {
- if (VDBG) {
- log("Network " + newNetwork.name() + " was already satisfying" +
- " request " + nri.request.requestId + ". No change.");
+ // Find and migrate to this Network any NetworkRequests for
+ // which this network is now the best.
+ final ArrayList<NetworkAgentInfo> removedRequests = new ArrayList<>();
+ final ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
+ for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry :
+ reassignedRequests.entrySet()) {
+ final NetworkRequestInfo nri = entry.getKey();
+ final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
+ final NetworkAgentInfo newSatisfier = entry.getValue();
+ if (newSatisfier != null) {
+ if (VDBG) log("rematch for " + newSatisfier.name());
+ if (previousSatisfier != null) {
+ if (VDBG || DDBG) {
+ log(" accepting network in place of " + previousSatisfier.name());
+ }
+ previousSatisfier.removeRequest(nri.request.requestId);
+ previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
+ removedRequests.add(previousSatisfier);
+ } else {
+ if (VDBG || DDBG) log(" accepting network in place of null");
}
+ newSatisfier.unlingerRequest(nri.request);
+ nri.mSatisfier = newSatisfier;
+ if (!newSatisfier.addRequest(nri.request)) {
+ Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
+ }
+ addedRequests.add(nri);
keep = true;
- continue;
- }
-
- // check if it satisfies the NetworkCapabilities
- if (VDBG) log(" checking if request is satisfied: " + nri.request);
- if (satisfies) {
- // next check if it's better than any current network we're using for
- // this request
- if (VDBG || DDBG) {
- log("currentScore = " +
- (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
- ", newScore = " + score);
- }
- if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
- if (VDBG) log("rematch for " + newNetwork.name());
- if (currentNetwork != null) {
- if (VDBG || DDBG){
- log(" accepting network in place of " + currentNetwork.name());
- }
- currentNetwork.removeRequest(nri.request.requestId);
- currentNetwork.lingerRequest(nri.request, now, mLingerDelayMs);
- affectedNetworks.add(currentNetwork);
- } else {
- if (VDBG || DDBG) log(" accepting network in place of null");
- }
- newNetwork.unlingerRequest(nri.request);
- setNetworkForRequest(nri.request.requestId, newNetwork);
- if (!newNetwork.addRequest(nri.request)) {
- Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
- }
- addedRequests.add(nri);
- keep = true;
- // Tell NetworkFactories about the new score, so they can stop
- // trying to connect if they know they cannot match it.
- // TODO - this could get expensive if we have a lot of requests for this
- // network. Think about if there is a way to reduce this. Push
- // netid->request mapping to each factory?
- sendUpdatedScoreToFactories(nri.request, newNetwork);
- if (isDefaultRequest(nri)) {
- isNewDefault = true;
- oldDefaultNetwork = currentNetwork;
- if (currentNetwork != null) {
- mLingerMonitor.noteLingerDefaultNetwork(currentNetwork, newNetwork);
- }
+ // Tell NetworkFactories about the new score, so they can stop
+ // trying to connect if they know they cannot match it.
+ // TODO - this could get expensive if we have a lot of requests for this
+ // network. Think about if there is a way to reduce this. Push
+ // netid->request mapping to each factory?
+ sendUpdatedScoreToFactories(nri.request, newSatisfier);
+ if (isDefaultRequest(nri)) {
+ isNewDefault = true;
+ oldDefaultNetwork = previousSatisfier;
+ if (previousSatisfier != null) {
+ mLingerMonitor.noteLingerDefaultNetwork(previousSatisfier, newSatisfier);
}
}
- } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
+ } else {
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
// mark it as no longer satisfying "nri". Because networks are processed by
// rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will
@@ -6415,13 +6422,14 @@
" request " + nri.request.requestId);
}
newNetwork.removeRequest(nri.request.requestId);
- if (currentNetwork == newNetwork) {
- clearNetworkForRequest(nri.request.requestId);
+ if (previousSatisfier == newNetwork) {
+ nri.mSatisfier = null;
+ if (isDefaultRequest(nri)) mDefaultNetworkNai = null;
sendUpdatedScoreToFactories(nri.request, null);
} else {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
newNetwork.name() +
- " without updating mNetworkForRequestId or factories!");
+ " without updating mSatisfier or factories!");
}
// TODO: Technically, sending CALLBACK_LOST here is
// incorrect if there is a replacement network currently
@@ -6433,6 +6441,7 @@
callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
}
}
+
if (isNewDefault) {
updateDataActivityTracking(newNetwork, oldDefaultNetwork);
// Notify system services that this network is up.
@@ -6472,7 +6481,7 @@
// Linger any networks that are no longer needed. This should be done after sending the
// available callback for newNetwork.
- for (NetworkAgentInfo nai : affectedNetworks) {
+ for (NetworkAgentInfo nai : removedRequests) {
updateLingerState(nai, now);
}
// Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
@@ -6540,66 +6549,43 @@
mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
}
}
- if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
- for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- if (unneeded(nai, UnneededFor.TEARDOWN)) {
- if (nai.getLingerExpiry() > 0) {
- // This network has active linger timers and no requests, but is not
- // lingering. Linger it.
- //
- // One way (the only way?) this can happen if this network is unvalidated
- // and became unneeded due to another network improving its score to the
- // point where this network will no longer be able to satisfy any requests
- // even if it validates.
- updateLingerState(nai, now);
- } else {
- if (DBG) log("Reaping " + nai.name());
- teardownUnneededNetwork(nai);
- }
- }
- }
- }
}
/**
* Attempt to rematch all Networks with NetworkRequests. This may result in Networks
* being disconnected.
- * @param changed If only one Network's score or capabilities have been modified since the last
- * time this function was called, pass this Network in this argument, otherwise pass
- * null.
- * @param oldScore If only one Network has been changed but its NetworkCapabilities have not
- * changed, pass in the Network's score (from getCurrentScore()) prior to the change via
- * this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if
- * {@code changed} is {@code null}. This is because NetworkCapabilities influence a
- * network's score.
*/
- private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
- // TODO: This may get slow. The "changed" parameter is provided for future optimization
- // to avoid the slowness. It is not simply enough to process just "changed", for
- // example in the case where "changed"'s score decreases and another network should begin
- // satisfying a NetworkRequest that "changed" currently satisfies.
-
- // Optimization: Only reprocess "changed" if its score improved. This is safe because it
- // can only add more NetworkRequests satisfied by "changed", and this is exactly what
- // rematchNetworkAndRequests() handles.
+ private void rematchAllNetworksAndRequests() {
+ // TODO: This may be slow, and should be optimized. Unfortunately at this moment the
+ // processing is network-major instead of request-major (the code iterates through all
+ // networks, then for each it iterates for all requests), which is a problem for re-scoring
+ // requests. Once the code has switched to a request-major iteration style, this can
+ // be optimized to only do the processing needed.
final long now = SystemClock.elapsedRealtime();
- if (changed != null && oldScore < changed.getCurrentScore()) {
- rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP, now);
- } else {
- final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
- new NetworkAgentInfo[mNetworkAgentInfos.size()]);
- // Rematch higher scoring networks first to prevent requests first matching a lower
- // scoring network and then a higher scoring network, which could produce multiple
- // callbacks and inadvertently unlinger networks.
- Arrays.sort(nais);
- for (NetworkAgentInfo nai : nais) {
- rematchNetworkAndRequests(nai,
- // Only reap the last time through the loop. Reaping before all rematching
- // is complete could incorrectly teardown a network that hasn't yet been
- // rematched.
- (nai != nais[nais.length-1]) ? ReapUnvalidatedNetworks.DONT_REAP
- : ReapUnvalidatedNetworks.REAP,
- now);
+ final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
+ new NetworkAgentInfo[mNetworkAgentInfos.size()]);
+ // Rematch higher scoring networks first to prevent requests first matching a lower
+ // scoring network and then a higher scoring network, which could produce multiple
+ // callbacks and inadvertently unlinger networks.
+ Arrays.sort(nais);
+ for (NetworkAgentInfo nai : nais) {
+ rematchNetworkAndRequests(nai, now);
+ }
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (unneeded(nai, UnneededFor.TEARDOWN)) {
+ if (nai.getLingerExpiry() > 0) {
+ // This network has active linger timers and no requests, but is not
+ // lingering. Linger it.
+ //
+ // One way (the only way?) this can happen if this network is unvalidated
+ // and became unneeded due to another network improving its score to the
+ // point where this network will no longer be able to satisfy any requests
+ // even if it validates.
+ updateLingerState(nai, now);
+ } else {
+ if (DBG) log("Reaping " + nai.name());
+ teardownUnneededNetwork(nai);
+ }
}
}
}
@@ -6698,8 +6684,7 @@
}
// Consider network even though it is not yet validated.
- final long now = SystemClock.elapsedRealtime();
- rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now);
+ rematchAllNetworksAndRequests();
// This has to happen after matching the requests, because callbacks are just requests.
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
@@ -6720,7 +6705,7 @@
state == NetworkInfo.State.SUSPENDED)) {
// going into or coming out of SUSPEND: re-score and notify
if (networkAgent.getCurrentScore() != oldScore) {
- rematchAllNetworksAndRequests(networkAgent, oldScore);
+ rematchAllNetworksAndRequests();
}
updateCapabilities(networkAgent.getCurrentScore(), networkAgent,
networkAgent.networkCapabilities);
@@ -6734,19 +6719,9 @@
}
private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
- int score = ns.getIntExtension(NetworkScore.LEGACY_SCORE);
- if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + score);
- if (score < 0) {
- loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
- "). Bumping score to min of 0");
- score = 0;
- }
-
- final int oldScore = nai.getCurrentScore();
+ if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + ns);
nai.setNetworkScore(ns);
-
- rematchAllNetworksAndRequests(nai, oldScore);
-
+ rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 80d7ac9..9a7a4e7 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -60,12 +60,9 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.TransferPipe;
-import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.DumpUtils;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -908,17 +905,6 @@
}
writer.println("Current scorer: " + currentScorer);
- sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
- @Override
- public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
- try {
- TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
- } catch (IOException | RemoteException e) {
- writer.println("Failed to dump score cache: " + e);
- }
- }
- }, getScoreCacheLists());
-
synchronized (mServiceConnectionLock) {
if (mServiceConnection != null) {
mServiceConnection.dump(fd, writer, args);
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
deleted file mode 100644
index 997178e..0000000
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2016 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.content.Context;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.IRecoverySystem;
-import android.os.IRecoverySystemProgressListener;
-import android.os.PowerManager;
-import android.os.RecoverySystem;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.util.Slog;
-
-import libcore.io.IoUtils;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- * The recovery system service is responsible for coordinating recovery related
- * functions on the device. It sets up (or clears) the bootloader control block
- * (BCB), which will be read by the bootloader and the recovery image. It also
- * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the
- * /data partition so that it can be accessed under the recovery image.
- */
-public final class RecoverySystemService extends SystemService {
- private static final String TAG = "RecoverySystemService";
- private static final boolean DEBUG = false;
-
- // The socket at /dev/socket/uncrypt to communicate with uncrypt.
- private static final String UNCRYPT_SOCKET = "uncrypt";
-
- // The init services that communicate with /system/bin/uncrypt.
- private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
- private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
- private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
-
- private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
-
- private static final Object sRequestLock = new Object();
-
- private Context mContext;
-
- public RecoverySystemService(Context context) {
- super(context);
- mContext = context;
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.RECOVERY_SERVICE, new BinderService());
- }
-
- private final class BinderService extends IRecoverySystem.Stub {
- @Override // Binder call
- public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
- if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
-
- synchronized (sRequestLock) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
-
- final boolean available = checkAndWaitForUncryptService();
- if (!available) {
- Slog.e(TAG, "uncrypt service is unavailable.");
- return false;
- }
-
- // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
- // uncrypt.
- RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
-
- try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
- uncryptFile.write(filename + "\n");
- } catch (IOException e) {
- Slog.e(TAG, "IOException when writing \"" +
- RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
- return false;
- }
-
- // Trigger uncrypt via init.
- SystemProperties.set("ctl.start", "uncrypt");
-
- // Connect to the uncrypt service socket.
- LocalSocket socket = connectService();
- if (socket == null) {
- Slog.e(TAG, "Failed to connect to uncrypt socket");
- return false;
- }
-
- // Read the status from the socket.
- DataInputStream dis = null;
- DataOutputStream dos = null;
- try {
- dis = new DataInputStream(socket.getInputStream());
- dos = new DataOutputStream(socket.getOutputStream());
- int lastStatus = Integer.MIN_VALUE;
- while (true) {
- int status = dis.readInt();
- // Avoid flooding the log with the same message.
- if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
- continue;
- }
- lastStatus = status;
-
- if (status >= 0 && status <= 100) {
- // Update status
- Slog.i(TAG, "uncrypt read status: " + status);
- if (listener != null) {
- try {
- listener.onProgress(status);
- } catch (RemoteException ignored) {
- Slog.w(TAG, "RemoteException when posting progress");
- }
- }
- if (status == 100) {
- Slog.i(TAG, "uncrypt successfully finished.");
- // Ack receipt of the final status code. uncrypt
- // waits for the ack so the socket won't be
- // destroyed before we receive the code.
- dos.writeInt(0);
- break;
- }
- } else {
- // Error in /system/bin/uncrypt.
- Slog.e(TAG, "uncrypt failed with status: " + status);
- // Ack receipt of the final status code. uncrypt waits
- // for the ack so the socket won't be destroyed before
- // we receive the code.
- dos.writeInt(0);
- return false;
- }
- }
- } catch (IOException e) {
- Slog.e(TAG, "IOException when reading status: ", e);
- return false;
- } finally {
- IoUtils.closeQuietly(dis);
- IoUtils.closeQuietly(dos);
- IoUtils.closeQuietly(socket);
- }
-
- return true;
- }
- }
-
- @Override // Binder call
- public boolean clearBcb() {
- if (DEBUG) Slog.d(TAG, "clearBcb");
- synchronized (sRequestLock) {
- return setupOrClearBcb(false, null);
- }
- }
-
- @Override // Binder call
- public boolean setupBcb(String command) {
- if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
- synchronized (sRequestLock) {
- return setupOrClearBcb(true, command);
- }
- }
-
- @Override // Binder call
- public void rebootRecoveryWithCommand(String command) {
- if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
- synchronized (sRequestLock) {
- if (!setupOrClearBcb(true, command)) {
- return;
- }
-
- // Having set up the BCB, go ahead and reboot.
- PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- pm.reboot(PowerManager.REBOOT_RECOVERY);
- }
- }
-
- /**
- * Check if any of the init services is still running. If so, we cannot
- * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
- * it may break the socket communication since init creates / deletes
- * the socket (/dev/socket/uncrypt) on service start / exit.
- */
- private boolean checkAndWaitForUncryptService() {
- for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
- final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
- final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
- final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
- final boolean busy = "running".equals(uncryptService) ||
- "running".equals(setupBcbService) || "running".equals(clearBcbService);
- if (DEBUG) {
- Slog.i(TAG, "retry: " + retry + " busy: " + busy +
- " uncrypt: [" + uncryptService + "]" +
- " setupBcb: [" + setupBcbService + "]" +
- " clearBcb: [" + clearBcbService + "]");
- }
-
- if (!busy) {
- return true;
- }
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted:", e);
- }
- }
-
- return false;
- }
-
- private LocalSocket connectService() {
- LocalSocket socket = new LocalSocket();
- boolean done = false;
- // The uncrypt socket will be created by init upon receiving the
- // service request. It may not be ready by this point. So we will
- // keep retrying until success or reaching timeout.
- for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
- try {
- socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
- LocalSocketAddress.Namespace.RESERVED));
- done = true;
- break;
- } catch (IOException ignored) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted:", e);
- }
- }
- }
- if (!done) {
- Slog.e(TAG, "Timed out connecting to uncrypt socket");
- return null;
- }
- return socket;
- }
-
- private boolean setupOrClearBcb(boolean isSetup, String command) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
-
- final boolean available = checkAndWaitForUncryptService();
- if (!available) {
- Slog.e(TAG, "uncrypt service is unavailable.");
- return false;
- }
-
- if (isSetup) {
- SystemProperties.set("ctl.start", "setup-bcb");
- } else {
- SystemProperties.set("ctl.start", "clear-bcb");
- }
-
- // Connect to the uncrypt service socket.
- LocalSocket socket = connectService();
- if (socket == null) {
- Slog.e(TAG, "Failed to connect to uncrypt socket");
- return false;
- }
-
- DataInputStream dis = null;
- DataOutputStream dos = null;
- try {
- dis = new DataInputStream(socket.getInputStream());
- dos = new DataOutputStream(socket.getOutputStream());
-
- // Send the BCB commands if it's to setup BCB.
- if (isSetup) {
- byte[] cmdUtf8 = command.getBytes("UTF-8");
- dos.writeInt(cmdUtf8.length);
- dos.write(cmdUtf8, 0, cmdUtf8.length);
- }
-
- // Read the status from the socket.
- int status = dis.readInt();
-
- // Ack receipt of the status code. uncrypt waits for the ack so
- // the socket won't be destroyed before we receive the code.
- dos.writeInt(0);
-
- if (status == 100) {
- Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
- " bcb successfully finished.");
- } else {
- // Error in /system/bin/uncrypt.
- Slog.e(TAG, "uncrypt failed with status: " + status);
- return false;
- }
- } catch (IOException e) {
- Slog.e(TAG, "IOException when communicating with uncrypt:", e);
- return false;
- } finally {
- IoUtils.closeQuietly(dis);
- IoUtils.closeQuietly(dos);
- IoUtils.closeQuietly(socket);
- }
-
- return true;
- }
- }
-}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 9693585..d1bc6af 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2803,12 +2803,6 @@
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
- // When a user has secure lock screen, require secret to actually unlock.
- // This check is mostly in place for emulation mode.
- if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
- throw new IllegalStateException("Secret required to unlock secure user " + userId);
- }
-
try {
mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
encodeBytes(secret));
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 30a3563..d1e4231 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.IntRange;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
@@ -41,6 +42,7 @@
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -53,6 +55,7 @@
import android.service.dreams.Sandman;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.R;
@@ -66,6 +69,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
final class UiModeManagerService extends SystemService {
private static final String TAG = UiModeManager.class.getSimpleName();
@@ -81,6 +87,7 @@
private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
private int mNightMode = UiModeManager.MODE_NIGHT_NO;
+ private Map<Integer, String> mCarModePackagePriority = new HashMap<>();
private boolean mCarModeEnabled = false;
private boolean mCharging = false;
private boolean mPowerSave = false;
@@ -338,15 +345,25 @@
private final IUiModeManager.Stub mService = new IUiModeManager.Stub() {
@Override
- public void enableCarMode(int flags) {
+ public void enableCarMode(@UiModeManager.EnableCarMode int flags,
+ @IntRange(from = 0) int priority, String callingPackage) {
if (isUiModeLocked()) {
Slog.e(TAG, "enableCarMode while UI mode is locked");
return;
}
+
+ if (priority != UiModeManager.DEFAULT_PRIORITY
+ && getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Enabling car mode with a priority requires "
+ + "permission ENTER_CAR_MODE_PRIORITIZED");
+ }
+
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- setCarModeLocked(true, flags);
+ setCarModeLocked(true, flags, priority, callingPackage);
if (mSystemReady) {
updateLocked(flags, 0);
}
@@ -356,16 +373,49 @@
}
}
+ /**
+ * This method is only kept around for the time being; the AIDL has an UnsupportedAppUsage
+ * tag which means this method is technically considered part of the greylist "API".
+ * @param flags
+ */
@Override
- public void disableCarMode(int flags) {
+ public void disableCarMode(@UiModeManager.DisableCarMode int flags) {
+ disableCarModeByCallingPackage(flags, null /* callingPackage */);
+ }
+
+ /**
+ * Handles requests to disable car mode.
+ * @param flags Disable car mode flags
+ * @param callingPackage
+ */
+ @Override
+ public void disableCarModeByCallingPackage(@UiModeManager.DisableCarMode int flags,
+ String callingPackage) {
if (isUiModeLocked()) {
Slog.e(TAG, "disableCarMode while UI mode is locked");
return;
}
+
+ // If the caller is the system, we will allow the DISABLE_CAR_MODE_ALL_PRIORITIES car
+ // mode flag to be specified; this is so that the user can disable car mode at all
+ // priorities using the persistent notification.
+ boolean isSystemCaller = Binder.getCallingUid() == Process.SYSTEM_UID;
+ final int carModeFlags =
+ isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES;
+
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- setCarModeLocked(false, 0);
+ // Determine if the caller has enabled car mode at a priority other than the
+ // default one. If they have, then attempt to disable at that priority.
+ int priority = mCarModePackagePriority.entrySet()
+ .stream()
+ .filter(e -> e.getValue().equals(callingPackage))
+ .findFirst()
+ .map(Map.Entry::getKey)
+ .orElse(UiModeManager.DEFAULT_PRIORITY);
+
+ setCarModeLocked(false, carModeFlags, priority, callingPackage);
if (mSystemReady) {
updateLocked(0, flags);
}
@@ -471,19 +521,32 @@
synchronized (mLock) {
pw.println("Current UI Mode Service state:");
pw.print(" mDockState="); pw.print(mDockState);
- pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+ pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+
pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" (");
- pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
- pw.print(" mNightModeLocked="); pw.print(mNightModeLocked);
- pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
- pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
- pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags);
- pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch);
+ pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
+ pw.print(" mNightModeLocked="); pw.println(mNightModeLocked);
+
+ pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
+ pw.print(" (carModeApps=");
+ for (Map.Entry<Integer, String> entry : mCarModePackagePriority.entrySet()) {
+ pw.print(entry.getKey());
+ pw.print(":");
+ pw.print(entry.getValue());
+ pw.print(" ");
+ }
+ pw.println("");
+ pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
+ pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags);
+ pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch);
+
pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
- pw.print(" mUiModeLocked="); pw.print(mUiModeLocked);
- pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+ pw.print(" mUiModeLocked="); pw.print(mUiModeLocked);
+ pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+
pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
- pw.print(" mSystemReady="); pw.println(mSystemReady);
+ pw.print(" mSystemReady="); pw.println(mSystemReady);
+
if (mTwilightManager != null) {
// We may not have a TwilightManager.
pw.print(" mTwilightService.getLastTwilightState()=");
@@ -506,12 +569,32 @@
}
}
- void setCarModeLocked(boolean enabled, int flags) {
- if (mCarModeEnabled != enabled) {
- mCarModeEnabled = enabled;
+ /**
+ * Updates the global car mode state.
+ * The device is considered to be in car mode if there exists an app at any priority level which
+ * has entered car mode.
+ *
+ * @param enabled {@code true} if the caller wishes to enable car mode, {@code false} otherwise.
+ * @param flags Flags used when enabling/disabling car mode.
+ * @param priority The priority level for entering or exiting car mode; defaults to
+ * {@link UiModeManager#DEFAULT_PRIORITY} for callers using
+ * {@link UiModeManager#enableCarMode(int)}. Callers using
+ * {@link UiModeManager#enableCarMode(int, int)} may specify a priority.
+ * @param packageName The package name of the app which initiated the request to enable or
+ * disable car mode.
+ */
+ void setCarModeLocked(boolean enabled, int flags, int priority, String packageName) {
+ if (enabled) {
+ enableCarMode(priority, packageName);
+ } else {
+ disableCarMode(flags, priority, packageName);
+ }
+ boolean isCarModeNowEnabled = isCarModeEnabled();
+ if (mCarModeEnabled != isCarModeNowEnabled) {
+ mCarModeEnabled = isCarModeNowEnabled;
// When exiting car mode, restore night mode from settings
- if (!mCarModeEnabled) {
+ if (!isCarModeNowEnabled) {
Context context = getContext();
updateNightModeFromSettings(context,
context.getResources(),
@@ -521,11 +604,102 @@
mCarModeEnableFlags = flags;
}
+ /**
+ * Handles disabling car mode.
+ * <p>
+ * Car mode can be disabled at a priority level if any of the following is true:
+ * 1. The priority being disabled is the {@link UiModeManager#DEFAULT_PRIORITY}.
+ * 2. The priority level is enabled and the caller is the app who originally enabled it.
+ * 3. The {@link UiModeManager#DISABLE_CAR_MODE_ALL_PRIORITIES} flag was specified, meaning all
+ * car mode priorities are disabled.
+ *
+ * @param flags Car mode flags.
+ * @param priority The priority level at which to disable car mode.
+ * @param packageName The calling package which initiated the request.
+ */
+ private void disableCarMode(int flags, int priority, String packageName) {
+ boolean isDisableAll = (flags & UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES) != 0;
+ boolean isPriorityTracked = mCarModePackagePriority.keySet().contains(priority);
+ boolean isDefaultPriority = priority == UiModeManager.DEFAULT_PRIORITY;
+ boolean isChangeAllowed =
+ // Anyone can disable the default priority.
+ isDefaultPriority
+ // If priority was enabled, only enabling package can disable it.
+ || isPriorityTracked && mCarModePackagePriority.get(priority).equals(packageName)
+ // Disable all priorities flag can disable all regardless.
+ || isDisableAll;
+ if (isChangeAllowed) {
+ Slog.d(TAG, "disableCarMode: disabling, priority=" + priority
+ + ", packageName=" + packageName);
+ if (isDisableAll) {
+ Set<Map.Entry<Integer, String>> entries =
+ new ArraySet<>(mCarModePackagePriority.entrySet());
+ mCarModePackagePriority.clear();
+
+ for (Map.Entry<Integer, String> entry : entries) {
+ notifyCarModeDisabled(entry.getKey(), entry.getValue());
+ }
+ } else {
+ mCarModePackagePriority.remove(priority);
+ notifyCarModeDisabled(priority, packageName);
+ }
+ }
+ }
+
+ /**
+ * Handles enabling car mode.
+ * <p>
+ * Car mode can be enabled at any priority if it has not already been enabled at that priority.
+ * The calling package is tracked for the first app which enters priority at the
+ * {@link UiModeManager#DEFAULT_PRIORITY}, though any app can disable it at that priority.
+ *
+ * @param priority The priority for enabling car mode.
+ * @param packageName The calling package which initiated the request.
+ */
+ private void enableCarMode(int priority, String packageName) {
+ boolean isPriorityTracked = mCarModePackagePriority.containsKey(priority);
+ boolean isPackagePresent = mCarModePackagePriority.containsValue(packageName);
+ if (!isPriorityTracked && !isPackagePresent) {
+ Slog.d(TAG, "enableCarMode: enabled at priority=" + priority + ", packageName="
+ + packageName);
+ mCarModePackagePriority.put(priority, packageName);
+ notifyCarModeEnabled(priority, packageName);
+ } else {
+ Slog.d(TAG, "enableCarMode: car mode at priority " + priority + " already enabled.");
+ }
+
+ }
+
+ private void notifyCarModeEnabled(int priority, String packageName) {
+ Intent intent = new Intent(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
+ intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName);
+ intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority);
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+ android.Manifest.permission.HANDLE_CAR_MODE_CHANGES);
+ }
+
+ private void notifyCarModeDisabled(int priority, String packageName) {
+ Intent intent = new Intent(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
+ intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName);
+ intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority);
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+ android.Manifest.permission.HANDLE_CAR_MODE_CHANGES);
+ }
+
+ /**
+ * Determines if car mode is enabled at any priority level.
+ * @return {@code true} if car mode is enabled, {@code false} otherwise.
+ */
+ private boolean isCarModeEnabled() {
+ return mCarModePackagePriority.size() > 0;
+ }
+
private void updateDockState(int newState) {
synchronized (mLock) {
if (newState != mDockState) {
mDockState = newState;
- setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0);
+ setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0,
+ UiModeManager.DEFAULT_PRIORITY, "" /* packageName */);
if (mSystemReady) {
updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index d622fb4..0db8495 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -28,8 +28,8 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.input.InputManager;
+import android.hardware.vibrator.IVibrator;
import android.hardware.vibrator.V1_0.EffectStrength;
-import android.hardware.vibrator.V1_4.Capabilities;
import android.icu.text.DateFormat;
import android.media.AudioAttributes;
import android.media.AudioManager;
@@ -1153,7 +1153,7 @@
long duration = vibratorPerformEffect(prebaked.getId(),
prebaked.getEffectStrength(), vib);
long timeout = duration;
- if ((mCapabilities & Capabilities.PERFORM_COMPLETION_CALLBACK) != 0) {
+ if ((mCapabilities & IVibrator.CAP_PERFORM_CALLBACK) != 0) {
timeout *= ASYNC_TIMEOUT_MULTIPLIER;
}
if (timeout > 0) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 83ad4e7..454941c 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -89,6 +89,7 @@
"/system/bin/drmserver",
"/system/bin/mediadrmserver",
"/system/bin/mediaserver",
+ "/system/bin/netd",
"/system/bin/sdcard",
"/system/bin/surfaceflinger",
"/system/bin/vold",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5af1480..d07ec48 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5276,11 +5276,14 @@
// Inform checkpointing systems of success
try {
+ // This line is needed to CTS test for the correct exception handling
+ // See b/138952436#comment36 for context
+ Slog.i(TAG, "About to commit checkpoint");
IStorageManager storageManager = PackageHelper.getStorageManager();
storageManager.commitChanges();
} catch (Exception e) {
PowerManager pm = (PowerManager)
- mInjector.getContext().getSystemService(Context.POWER_SERVICE);
+ mContext.getSystemService(Context.POWER_SERVICE);
pm.reboot("Checkpoint commit failed");
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 709f3f8..ae5ad7e 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -126,6 +126,12 @@
}
@Override
+ public void clearOverridesForTest(String packageName) {
+ CompatConfig config = CompatConfig.get();
+ config.removePackageOverrides(packageName);
+ }
+
+ @Override
public boolean clearOverride(long changeId, String packageName) {
boolean existed = CompatConfig.get().removeOverride(changeId, packageName);
killPackage(packageName);
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index d13e675..bc83780 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -18,6 +18,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.app.Notification;
@@ -89,14 +90,22 @@
mNotificationTypeMap = new SparseIntArray();
}
+ @VisibleForTesting
+ protected static int approximateTransportType(NetworkAgentInfo nai) {
+ return nai.isVPN() ? TRANSPORT_VPN : getFirstTransportType(nai);
+ }
+
// TODO: deal more gracefully with multi-transport networks.
private static int getFirstTransportType(NetworkAgentInfo nai) {
+ // TODO: The range is wrong, the safer and correct way is to change the range from
+ // MIN_TRANSPORT to MAX_TRANSPORT.
for (int i = 0; i < 64; i++) {
if (nai.networkCapabilities.hasTransport(i)) return i;
}
return -1;
}
+ // TODO: Remove @TransportType or change it to @Transport.
private static String getTransportName(@TransportType int transportType) {
Resources r = Resources.getSystem();
String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
@@ -146,7 +155,7 @@
final int transportType;
final String name;
if (nai != null) {
- transportType = getFirstTransportType(nai);
+ transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo();
name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
// Only notify for Internet-capable networks.
@@ -175,7 +184,7 @@
tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
- Resources r = Resources.getSystem();
+ Resources r = mContext.getResources();
final CharSequence title;
final CharSequence details;
int icon = getIcon(transportType, notifyType);
@@ -239,7 +248,7 @@
details = r.getString(R.string.captive_portal_logged_in_detailed);
} else if (notifyType == NotificationType.NETWORK_SWITCH) {
String fromTransport = getTransportName(transportType);
- String toTransport = getTransportName(getFirstTransportType(switchToNai));
+ String toTransport = getTransportName(approximateTransportType(switchToNai));
title = r.getString(R.string.network_switch_metered, toTransport);
details = r.getString(R.string.network_switch_metered_detail, toTransport,
fromTransport);
@@ -340,8 +349,8 @@
}
public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
- String fromTransport = getTransportName(getFirstTransportType(fromNai));
- String toTransport = getTransportName(getFirstTransportType(toNai));
+ String fromTransport = getTransportName(approximateTransportType(fromNai));
+ String toTransport = getTransportName(approximateTransportType(toNai));
String text = mContext.getResources().getString(
R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index f326f1d..ec48713 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -22,11 +22,11 @@
import android.text.TextUtils;
import android.util.ArraySet;
+import dalvik.system.VMRuntime;
+
import java.util.ArrayList;
import java.util.List;
-import dalvik.system.VMRuntime;
-
/**
* Provides various methods for obtaining and converting of instruction sets.
*
@@ -113,12 +113,15 @@
return allInstructionSets;
}
- public static String getPrimaryInstructionSet(ApplicationInfo info) {
- if (info.primaryCpuAbi == null) {
+ /**
+ * Calculates the primary instruction set based on the computed Abis of a given package.
+ */
+ public static String getPrimaryInstructionSet(PackageAbiHelper.Abis abis) {
+ if (abis.primary == null) {
return getPreferredInstructionSet();
}
- return VMRuntime.getInstructionSet(info.primaryCpuAbi);
+ return VMRuntime.getInstructionSet(abis.primary);
}
}
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 62ea95b..f8c173f 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -32,6 +32,9 @@
per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com
per-file UserManagerService.java = omakoto@google.com, yamasani@google.com
per-file UserRestrictionsUtils.java = omakoto@google.com, rubinxu@google.com, sandness@google.com, yamasani@google.com
+per-file UserSystemPackageInstaller.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
+per-file UserTypeDetails.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
+per-file UserTypeFactory.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
# security
per-file KeySetHandle.java = cbrubaker@google.com, nnk@google.com
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
new file mode 100644
index 0000000..6f46564
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.util.Pair;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.Set;
+
+@VisibleForTesting
+interface PackageAbiHelper {
+ /**
+ * Derive and get the location of native libraries for the given package,
+ * which varies depending on where and how the package was installed.
+ */
+ NativeLibraryPaths getNativeLibraryPaths(
+ PackageParser.Package pkg, File appLib32InstallDir);
+
+ /**
+ * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
+ * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
+ * validate any of this information, and instead assume that the system was built sensibly.
+ */
+ Abis getBundledAppAbis(PackageParser.Package pkg);
+
+ /**
+ * Derive the ABI of a non-system package located at {@code pkg}. This information
+ * is derived purely on the basis of the contents of {@code pkg} and {@code cpuAbiOverride}.
+ *
+ * If {@code extractLibs} is true, native libraries are extracted from the app if required.
+ */
+ Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+ PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+ throws PackageManagerException;
+
+ /**
+ * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
+ * match. i.e, so that all packages can be run inside a single process if required.
+ *
+ * Optionally, callers can pass in a parsed package via {@code scannedPackage} in which case
+ * this function will either try and make the ABI for all packages in
+ * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+ * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+ * variant is used when installing or updating a package that belongs to a shared user.
+ *
+ * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+ * adds unnecessary complexity.
+ *
+ * @return the calculated primary abi that should be set for all non-specified packages
+ * belonging to the shared user.
+ */
+ @Nullable
+ String getAdjustedAbiForSharedUser(
+ Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+
+ /**
+ * The native library paths and related properties that should be set on a
+ * {@link android.content.pm.PackageParser.Package}.
+ */
+ final class NativeLibraryPaths {
+ public final String nativeLibraryRootDir;
+ public final boolean nativeLibraryRootRequiresIsa;
+ public final String nativeLibraryDir;
+ public final String secondaryNativeLibraryDir;
+
+ @VisibleForTesting
+ NativeLibraryPaths(String nativeLibraryRootDir,
+ boolean nativeLibraryRootRequiresIsa, String nativeLibraryDir,
+ String secondaryNativeLibraryDir) {
+ this.nativeLibraryRootDir = nativeLibraryRootDir;
+ this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+ this.nativeLibraryDir = nativeLibraryDir;
+ this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+ }
+
+ public void applyTo(PackageParser.Package pkg) {
+ pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+ pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+ pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
+ pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+ }
+ }
+
+ /**
+ * The primary and secondary ABIs that should be set on a package and its package setting.
+ */
+ final class Abis {
+ public final String primary;
+ public final String secondary;
+
+ @VisibleForTesting
+ Abis(String primary, String secondary) {
+ this.primary = primary;
+ this.secondary = secondary;
+ }
+
+ Abis(PackageParser.Package pkg) {
+ this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
+ }
+
+ public void applyTo(PackageParser.Package pkg) {
+ pkg.applicationInfo.primaryCpuAbi = primary;
+ pkg.applicationInfo.secondaryCpuAbi = secondary;
+ }
+ public void applyTo(PackageSetting pkgSetting) {
+ // pkgSetting might be null during rescan following uninstall of updates
+ // to a bundled app, so accommodate that possibility. The settings in
+ // that case will be established later from the parsed package.
+ //
+ // If the settings aren't null, sync them up with what we've derived.
+ if (pkgSetting != null) {
+ pkgSetting.primaryCpuAbiString = primary;
+ pkgSetting.secondaryCpuAbiString = secondary;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
new file mode 100644
index 0000000..1d3d24c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+final class PackageAbiHelperImpl implements PackageAbiHelper {
+
+ private static String calculateBundledApkRoot(final String codePathString) {
+ final File codePath = new File(codePathString);
+ final File codeRoot;
+ if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
+ codeRoot = Environment.getRootDirectory();
+ } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
+ codeRoot = Environment.getOemDirectory();
+ } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
+ codeRoot = Environment.getVendorDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
+ } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+ codeRoot = Environment.getProductDirectory();
+ } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
+ codeRoot = Environment.getSystemExtDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
+ } else {
+ // Unrecognized code path; take its top real segment as the apk root:
+ // e.g. /something/app/blah.apk => /something
+ try {
+ File f = codePath.getCanonicalFile();
+ File parent = f.getParentFile(); // non-null because codePath is a file
+ File tmp;
+ while ((tmp = parent.getParentFile()) != null) {
+ f = parent;
+ parent = tmp;
+ }
+ codeRoot = f;
+ Slog.w(PackageManagerService.TAG, "Unrecognized code path "
+ + codePath + " - using " + codeRoot);
+ } catch (IOException e) {
+ // Can't canonicalize the code path -- shenanigans?
+ Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
+ return Environment.getRootDirectory().getPath();
+ }
+ }
+ return codeRoot.getPath();
+ }
+
+ // Utility method that returns the relative package path with respect
+ // to the installation directory. Like say for /data/data/com.test-1.apk
+ // string com.test-1 is returned.
+ private static String deriveCodePathName(String codePath) {
+ if (codePath == null) {
+ return null;
+ }
+ final File codeFile = new File(codePath);
+ final String name = codeFile.getName();
+ if (codeFile.isDirectory()) {
+ return name;
+ } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
+ final int lastDot = name.lastIndexOf('.');
+ return name.substring(0, lastDot);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK");
+ return null;
+ }
+ }
+
+ private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
+ PackageManagerException {
+ if (copyRet < 0) {
+ if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
+ && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+ throw new PackageManagerException(copyRet, message);
+ }
+ }
+ }
+
+ @Override
+ public NativeLibraryPaths getNativeLibraryPaths(
+ PackageParser.Package pkg, File appLib32InstallDir) {
+ return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
+ pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+ pkg.applicationInfo.isUpdatedSystemApp());
+ }
+
+ private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
+ final File appLib32InstallDir, final String codePath, final String sourceDir,
+ final boolean isSystemApp, final boolean isUpdatedSystemApp) {
+ final File codeFile = new File(codePath);
+ final boolean bundledApp = isSystemApp && !isUpdatedSystemApp;
+
+ final String nativeLibraryRootDir;
+ final boolean nativeLibraryRootRequiresIsa;
+ final String nativeLibraryDir;
+ final String secondaryNativeLibraryDir;
+
+ if (isApkFile(codeFile)) {
+ // Monolithic install
+ if (bundledApp) {
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateBundledApkRoot(sourceDir);
+ final boolean is64Bit = VMRuntime.is64BitInstructionSet(
+ getPrimaryInstructionSet(abis));
+
+ // This is a bundled system app so choose the path based on the ABI.
+ // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
+ // is just the default path.
+ final String apkName = deriveCodePathName(codePath);
+ final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
+ nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
+ apkName).getAbsolutePath();
+
+ if (abis.secondary != null) {
+ final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
+ secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
+ secondaryLibDir, apkName).getAbsolutePath();
+ } else {
+ secondaryNativeLibraryDir = null;
+ }
+ } else {
+ final String apkName = deriveCodePathName(codePath);
+ nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
+ .getAbsolutePath();
+ secondaryNativeLibraryDir = null;
+ }
+
+ nativeLibraryRootRequiresIsa = false;
+ nativeLibraryDir = nativeLibraryRootDir;
+ } else {
+ // Cluster install
+ nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
+ nativeLibraryRootRequiresIsa = true;
+
+ nativeLibraryDir = new File(nativeLibraryRootDir,
+ getPrimaryInstructionSet(abis)).getAbsolutePath();
+
+ if (abis.secondary != null) {
+ secondaryNativeLibraryDir = new File(nativeLibraryRootDir,
+ VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath();
+ } else {
+ secondaryNativeLibraryDir = null;
+ }
+ }
+ return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa,
+ nativeLibraryDir, secondaryNativeLibraryDir);
+ }
+
+ @Override
+ public Abis getBundledAppAbis(PackageParser.Package pkg) {
+ final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+ final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
+ return abis;
+ }
+
+ /**
+ * Deduces the ABI of a bundled app and sets the relevant fields on the
+ * parsed pkg object.
+ *
+ * @param apkRoot the root of the installed apk, something like {@code /system} or
+ * {@code /oem} under which system libraries are installed.
+ * @param apkName the name of the installed package.
+ */
+ private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
+ final File codeFile = new File(pkg.codePath);
+
+ final boolean has64BitLibs;
+ final boolean has32BitLibs;
+
+ final String primaryCpuAbi;
+ final String secondaryCpuAbi;
+ if (isApkFile(codeFile)) {
+ // Monolithic install
+ has64BitLibs =
+ (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
+ has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
+ } else {
+ // Cluster install
+ final File rootDir = new File(codeFile, LIB_DIR_NAME);
+ if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
+ && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
+ final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
+ has64BitLibs = (new File(rootDir, isa)).exists();
+ } else {
+ has64BitLibs = false;
+ }
+ if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
+ && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
+ final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
+ has32BitLibs = (new File(rootDir, isa)).exists();
+ } else {
+ has32BitLibs = false;
+ }
+ }
+
+ if (has64BitLibs && !has32BitLibs) {
+ // The package has 64 bit libs, but not 32 bit libs. Its primary
+ // ABI should be 64 bit. We can safely assume here that the bundled
+ // native libraries correspond to the most preferred ABI in the list.
+
+ primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ secondaryCpuAbi = null;
+ } else if (has32BitLibs && !has64BitLibs) {
+ // The package has 32 bit libs but not 64 bit libs. Its primary
+ // ABI should be 32 bit.
+
+ primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ secondaryCpuAbi = null;
+ } else if (has32BitLibs && has64BitLibs) {
+ // The application has both 64 and 32 bit bundled libraries. We check
+ // here that the app declares multiArch support, and warn if it doesn't.
+ //
+ // We will be lenient here and record both ABIs. The primary will be the
+ // ABI that's higher on the list, i.e, a device that's configured to prefer
+ // 64 bit apps will see a 64 bit primary ABI,
+
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+ Slog.e(PackageManagerService.TAG,
+ "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
+ }
+
+ if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
+ primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ } else {
+ primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ }
+ } else {
+ primaryCpuAbi = null;
+ secondaryCpuAbi = null;
+ }
+ return new Abis(primaryCpuAbi, secondaryCpuAbi);
+ }
+
+ @Override
+ public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+ PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+ throws PackageManagerException {
+ // Give ourselves some initial paths; we'll come back for another
+ // pass once we've determined ABI below.
+ final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
+ PackageManagerService.sAppLib32InstallDir, pkg.codePath,
+ pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+ pkg.applicationInfo.isUpdatedSystemApp());
+
+ // We shouldn't attempt to extract libs from system app when it was not updated.
+ if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
+ extractLibs = false;
+ }
+
+ final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
+ final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
+
+ String primaryCpuAbi = null;
+ String secondaryCpuAbi = null;
+
+ NativeLibraryHelper.Handle handle = null;
+ try {
+ handle = NativeLibraryHelper.Handle.create(pkg);
+ // TODO(multiArch): This can be null for apps that didn't go through the
+ // usual installation process. We can calculate it again, like we
+ // do during install time.
+ //
+ // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
+ // unnecessary.
+ final File nativeLibraryRoot = new File(nativeLibraryRootStr);
+
+ // Null out the abis so that they can be recalculated.
+ primaryCpuAbi = null;
+ secondaryCpuAbi = null;
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+ // Warn if we've set an abiOverride for multi-lib packages..
+ // By definition, we need to copy both 32 and 64 bit libraries for
+ // such packages.
+ if (pkg.cpuAbiOverride != null
+ && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+ Slog.w(PackageManagerService.TAG,
+ "Ignoring abiOverride for multi arch application.");
+ }
+
+ int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
+ int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ abi32 = NativeLibraryHelper.findSupportedAbi(
+ handle, Build.SUPPORTED_32_BIT_ABIS);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Shared library native code should be in the APK zip aligned
+ if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library native lib extraction not supported");
+ }
+
+ maybeThrowExceptionForMultiArchCopy(
+ "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ abi64 = NativeLibraryHelper.findSupportedAbi(
+ handle, Build.SUPPORTED_64_BIT_ABIS);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ maybeThrowExceptionForMultiArchCopy(
+ "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+
+ if (abi64 >= 0) {
+ // Shared library native libs should be in the APK zip aligned
+ if (extractLibs && pkg.isLibrary()) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library native lib extraction not supported");
+ }
+ primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+ }
+
+ if (abi32 >= 0) {
+ final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+ if (abi64 >= 0) {
+ if (pkg.use32bitAbi) {
+ secondaryCpuAbi = primaryCpuAbi;
+ primaryCpuAbi = abi;
+ } else {
+ secondaryCpuAbi = abi;
+ }
+ } else {
+ primaryCpuAbi = abi;
+ }
+ }
+ } else {
+ String[] abiList = (cpuAbiOverride != null)
+ ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
+
+ // Enable gross and lame hacks for apps that are built with old
+ // SDK tools. We must scan their APKs for renderscript bitcode and
+ // not launch them if it's present. Don't bother checking on devices
+ // that don't have 64 bit support.
+ boolean needsRenderScriptOverride = false;
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
+ && NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
+ needsRenderScriptOverride = true;
+ }
+
+ final int copyRet;
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Error unpackaging native libs for app, errorCode=" + copyRet);
+ }
+
+ if (copyRet >= 0) {
+ // Shared libraries that have native libs must be multi-architecture
+ if (pkg.isLibrary()) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library with native libs must be multiarch");
+ }
+ primaryCpuAbi = abiList[copyRet];
+ } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
+ && cpuAbiOverride != null) {
+ primaryCpuAbi = cpuAbiOverride;
+ } else if (needsRenderScriptOverride) {
+ primaryCpuAbi = abiList[0];
+ }
+ }
+ } catch (IOException ioe) {
+ Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
+ } finally {
+ IoUtils.closeQuietly(handle);
+ }
+
+ // Now that we've calculated the ABIs and determined if it's an internal app,
+ // we will go ahead and populate the nativeLibraryPath.
+
+ final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
+ return new Pair<>(abis,
+ getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
+ pkg.codePath, pkg.applicationInfo.sourceDir,
+ pkg.applicationInfo.isSystemApp(),
+ pkg.applicationInfo.isUpdatedSystemApp()));
+ }
+
+ /**
+ * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
+ * i.e, so that all packages can be run inside a single process if required.
+ *
+ * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
+ * this function will either try and make the ABI for all packages in
+ * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+ * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+ * variant is used when installing or updating a package that belongs to a shared user.
+ *
+ * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+ * adds unnecessary complexity.
+ */
+ @Override
+ @Nullable
+ public String getAdjustedAbiForSharedUser(
+ Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+ String requiredInstructionSet = null;
+ if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+ requiredInstructionSet = VMRuntime.getInstructionSet(
+ scannedPackage.applicationInfo.primaryCpuAbi);
+ }
+
+ PackageSetting requirer = null;
+ for (PackageSetting ps : packagesForUser) {
+ // If packagesForUser contains scannedPackage, we skip it. This will happen
+ // when scannedPackage is an update of an existing package. Without this check,
+ // we will never be able to change the ABI of any package belonging to a shared
+ // user, even if it's compatible with other packages.
+ if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
+ continue;
+ }
+ if (ps.primaryCpuAbiString == null) {
+ continue;
+ }
+
+ final String instructionSet =
+ VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
+ if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) {
+ // We have a mismatch between instruction sets (say arm vs arm64) warn about
+ // this but there's not much we can do.
+ String errorMessage = "Instruction set mismatch, "
+ + ((requirer == null) ? "[caller]" : requirer)
+ + " requires " + requiredInstructionSet + " whereas " + ps
+ + " requires " + instructionSet;
+ Slog.w(PackageManagerService.TAG, errorMessage);
+ }
+
+ if (requiredInstructionSet == null) {
+ requiredInstructionSet = instructionSet;
+ requirer = ps;
+ }
+ }
+
+ if (requiredInstructionSet == null) {
+ return null;
+ }
+ final String adjustedAbi;
+ if (requirer != null) {
+ // requirer != null implies that either scannedPackage was null or that
+ // scannedPackage did not require an ABI, in which case we have to adjust
+ // scannedPackage to match the ABI of the set (which is the same as
+ // requirer's ABI)
+ adjustedAbi = requirer.primaryCpuAbiString;
+ } else {
+ // requirer == null implies that we're updating all ABIs in the set to
+ // match scannedPackage.
+ adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+ }
+ return adjustedAbi;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6f9a918..4eddb930 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -23,6 +23,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
+import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
@@ -1484,7 +1485,29 @@
"Too many files for apex install");
}
- mResolvedBaseFile = addedFiles[0];
+ try {
+ resolveStageDirLocked();
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+ "Failed to resolve stage location", e);
+ }
+
+ File addedFile = addedFiles[0]; // there is only one file
+
+ // Ensure file name has proper suffix
+ final String sourceName = addedFile.getName();
+ final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
+ ? sourceName
+ : sourceName + APEX_FILE_EXTENSION;
+ if (!FileUtils.isValidExtFilename(targetName)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Invalid filename: " + targetName);
+ }
+
+ final File targetFile = new File(mResolvedStageDir, targetName);
+ resolveAndStageFile(addedFile, targetFile);
+
+ mResolvedBaseFile = targetFile;
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d7d7345..8d31b34 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -93,14 +93,12 @@
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
-import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
@@ -278,6 +276,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
@@ -433,7 +432,7 @@
// user, but by default initialize to this.
public static final boolean DEBUG_DEXOPT = false;
- private static final boolean DEBUG_ABI_SELECTION = false;
+ static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_APP_DATA = false;
@@ -663,7 +662,8 @@
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
/** Directory where installed application's 32-bit native libraries are copied. */
- private static final File sAppLib32InstallDir =
+ @VisibleForTesting
+ static final File sAppLib32InstallDir =
new File(Environment.getDataDirectory(), "app-lib");
// ----------------------------------------------------------------
@@ -754,6 +754,30 @@
private final ApexManager mApexManager;
+ private final Injector mInjector;
+
+ /**
+ * Unit tests will instantiate and / or extend to mock dependencies / behaviors.
+ */
+ @VisibleForTesting
+ static class Injector {
+ private final UserManagerInternal mUserManager;
+ private final PackageAbiHelper mAbiHelper;
+
+ Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) {
+ mUserManager = userManager;
+ mAbiHelper = abiHelper;
+ }
+
+ public UserManagerInternal getUserManager() {
+ return mUserManager;
+ }
+
+ public PackageAbiHelper getAbiHelper() {
+ return mAbiHelper;
+ }
+ }
+
class PackageParserCallback implements PackageParser.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -2093,8 +2117,8 @@
// survive long enough to benefit of background optimizations.
for (int userId : firstUserIds) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
- // There's a race currently where some install events may interleave with an uninstall.
- // This can lead to package info being null (b/36642664).
+ // There's a race currently where some install events may interleave with an
+ // uninstall. This can lead to package info being null (b/36642664).
if (info != null) {
mDexManager.notifyPackageInstalled(info, userId);
}
@@ -2164,6 +2188,7 @@
* external/removable/unprotected storage.
* @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
* corresponding {@link StorageEnum} storage type value if it is.
+ * corresponding {@link StorageEnum} storage type value if it is.
*/
private static int getPackageExternalStorageType(VolumeInfo packageVolume,
boolean packageIsExternal) {
@@ -2421,6 +2446,11 @@
mPermissionManager.getPermissionSettings(), mPackages);
}
}
+
+ // TODO(b/137961986): We should pass this via constructor, but would first need to create
+ // a packages lock that could also be passed in.
+ mInjector = new Injector(getUserManagerInternal(), new PackageAbiHelperImpl());
+
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
@@ -3128,7 +3158,9 @@
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
final List<String> changedAbiCodePath =
- adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
+ applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
+ mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
+ setting.packages, null /*scannedPackage*/));
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
final String codePathString = changedAbiCodePath.get(i);
@@ -9397,7 +9429,8 @@
null /* originalPkgSetting */, null, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
- final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+ final ScanResult scanResult =
+ scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
}
@@ -10759,7 +10792,8 @@
}
/** The result of a package scan. */
- private static class ScanResult {
+ @VisibleForTesting
+ static class ScanResult {
/** The request that initiated the scan that produced this result. */
public final ScanRequest request;
/** Whether or not the package scan was successful */
@@ -10798,7 +10832,8 @@
}
/** A package to be scanned */
- private static class ScanRequest {
+ @VisibleForTesting
+ static class ScanRequest {
/** The parsed package */
@NonNull public final PackageParser.Package pkg;
/** The package this package replaces */
@@ -10991,7 +11026,7 @@
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
originalPkgSetting, realPkgName, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
- return scanPackageOnlyLI(request, mFactoryTest, currentTime);
+ return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
}
}
@@ -11216,20 +11251,70 @@
}
/**
+ * Applies the adjusted ABI calculated by
+ * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
+ * relevant packages and settings.
+ * @param sharedUserSetting The {@code SharedUserSetting} to adjust
+ * @param scannedPackage the package being scanned or null
+ * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper}
+ * @return the list of code paths that belong to packages that had their ABIs adjusted.
+ */
+ private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
+ PackageParser.Package scannedPackage, String adjustedAbi) {
+ if (scannedPackage != null) {
+ scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+ }
+ List<String> changedAbiCodePath = null;
+ for (PackageSetting ps : sharedUserSetting.packages) {
+ if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+ if (ps.primaryCpuAbiString != null) {
+ continue;
+ }
+
+ ps.primaryCpuAbiString = adjustedAbi;
+ if (ps.pkg != null && ps.pkg.applicationInfo != null
+ && !TextUtils.equals(
+ adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
+ ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+ if (DEBUG_ABI_SELECTION) {
+ Slog.i(TAG,
+ "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+ + " (scannedPackage="
+ + (scannedPackage != null ? scannedPackage : "null")
+ + ")");
+ }
+ if (changedAbiCodePath == null) {
+ changedAbiCodePath = new ArrayList<>();
+ }
+ changedAbiCodePath.add(ps.codePathString);
+ }
+ }
+ }
+ return changedAbiCodePath;
+ }
+
+
+ /**
* Just scans the package without any side effects.
* <p>Not entirely true at the moment. There is still one side effect -- this
* method potentially modifies a live {@link PackageSetting} object representing
* the package being scanned. This will be resolved in the future.
*
+ * @param injector injector for acquiring dependencies
* @param request Information about the package to be scanned
* @param isUnderFactoryTest Whether or not the device is under factory test
* @param currentTime The current time, in millis
* @return The results of the scan
*/
@GuardedBy("mInstallLock")
- private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ @VisibleForTesting
+ @NonNull
+ static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ Injector injector,
boolean isUnderFactoryTest, long currentTime)
- throws PackageManagerException {
+ throws PackageManagerException {
+ final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
+ final UserManagerInternal userManager = injector.getUserManager();
final PackageParser.Package pkg = request.pkg;
PackageSetting pkgSetting = request.pkgSetting;
final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -11335,7 +11420,7 @@
if (!createNewPackage) {
final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
- setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+ setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp);
}
// TODO(patb): see if we can do away with disabled check here.
if (disabledPkgSetting != null
@@ -11381,7 +11466,10 @@
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+ final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
+ packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+ derivedAbi.first.applyTo(pkg);
+ derivedAbi.second.applyTo(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Some system apps still use directory structure for native libraries
@@ -11389,8 +11477,13 @@
// structure. Try to detect abi based on directory structure.
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
- setBundledAppAbisAndRoots(pkg, pkgSetting);
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
+ pkg);
+ abis.applyTo(pkg);
+ abis.applyTo(pkgSetting);
+ final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+ packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(pkg);
}
} else {
// This is not a first boot or an upgrade, don't bother deriving the
@@ -11399,7 +11492,9 @@
pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+ packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(pkg);
if (DEBUG_ABI_SELECTION) {
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
@@ -11420,7 +11515,9 @@
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+ packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(pkg);
}
// This is a special case for the "system" package, where the ABI is
@@ -11474,8 +11571,9 @@
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
- changedAbiCodePath =
- adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
+ changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
+ packageAbiHelper.getAdjustedAbiForSharedUser(
+ pkgSetting.sharedUser.packages, pkg));
}
if (isUnderFactoryTest && pkg.requestedPermissions.contains(
@@ -12325,264 +12423,6 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- /**
- * Derive the ABI of a non-system package located at {@code scanFile}. This information
- * is derived purely on the basis of the contents of {@code scanFile} and
- * {@code cpuAbiOverride}.
- *
- * If {@code extractLibs} is true, native libraries are extracted from the app if required.
- */
- private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
- boolean extractLibs)
- throws PackageManagerException {
- // Give ourselves some initial paths; we'll come back for another
- // pass once we've determined ABI below.
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
-
- // We shouldn't attempt to extract libs from system app when it was not updated.
- if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
- extractLibs = false;
- }
-
- final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
- final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
-
- NativeLibraryHelper.Handle handle = null;
- try {
- handle = NativeLibraryHelper.Handle.create(pkg);
- // TODO(multiArch): This can be null for apps that didn't go through the
- // usual installation process. We can calculate it again, like we
- // do during install time.
- //
- // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
- // unnecessary.
- final File nativeLibraryRoot = new File(nativeLibraryRootStr);
-
- // Null out the abis so that they can be recalculated.
- pkg.applicationInfo.primaryCpuAbi = null;
- pkg.applicationInfo.secondaryCpuAbi = null;
- if (isMultiArch(pkg.applicationInfo)) {
- // Warn if we've set an abiOverride for multi-lib packages..
- // By definition, we need to copy both 32 and 64 bit libraries for
- // such packages.
- if (pkg.cpuAbiOverride != null
- && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
- Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
- }
-
- int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
- int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
- if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- // Shared library native code should be in the APK zip aligned
- if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library native lib extraction not supported");
- }
-
- maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 32 bit native libs for multiarch app.", abi32);
-
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 64 bit native libs for multiarch app.", abi64);
-
- if (abi64 >= 0) {
- // Shared library native libs should be in the APK zip aligned
- if (extractLibs && pkg.isLibrary()) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library native lib extraction not supported");
- }
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
- }
-
- if (abi32 >= 0) {
- final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
- if (abi64 >= 0) {
- if (pkg.use32bitAbi) {
- pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
- pkg.applicationInfo.primaryCpuAbi = abi;
- } else {
- pkg.applicationInfo.secondaryCpuAbi = abi;
- }
- } else {
- pkg.applicationInfo.primaryCpuAbi = abi;
- }
- }
- } else {
- String[] abiList = (cpuAbiOverride != null) ?
- new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
-
- // Enable gross and lame hacks for apps that are built with old
- // SDK tools. We must scan their APKs for renderscript bitcode and
- // not launch them if it's present. Don't bother checking on devices
- // that don't have 64 bit support.
- boolean needsRenderScriptOverride = false;
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
- NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
- abiList = Build.SUPPORTED_32_BIT_ABIS;
- needsRenderScriptOverride = true;
- }
-
- final int copyRet;
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
- if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Error unpackaging native libs for app, errorCode=" + copyRet);
- }
-
- if (copyRet >= 0) {
- // Shared libraries that have native libs must be multi-architecture
- if (pkg.isLibrary()) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library with native libs must be multiarch");
- }
- pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
- } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
- pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
- } else if (needsRenderScriptOverride) {
- pkg.applicationInfo.primaryCpuAbi = abiList[0];
- }
- }
- } catch (IOException ioe) {
- Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
- } finally {
- IoUtils.closeQuietly(handle);
- }
-
- // Now that we've calculated the ABIs and determined if it's an internal app,
- // we will go ahead and populate the nativeLibraryPath.
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
- }
-
- /**
- * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
- * i.e, so that all packages can be run inside a single process if required.
- *
- * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
- * this function will either try and make the ABI for all packages in {@code packagesForUser}
- * match {@code scannedPackage} or will update the ABI of {@code scannedPackage} to match
- * the ABI selected for {@code packagesForUser}. This variant is used when installing or
- * updating a package that belongs to a shared user.
- *
- * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
- * adds unnecessary complexity.
- */
- private static @Nullable List<String> adjustCpuAbisForSharedUserLPw(
- Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
- List<String> changedAbiCodePath = null;
- String requiredInstructionSet = null;
- if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
- requiredInstructionSet = VMRuntime.getInstructionSet(
- scannedPackage.applicationInfo.primaryCpuAbi);
- }
-
- PackageSetting requirer = null;
- for (PackageSetting ps : packagesForUser) {
- // If packagesForUser contains scannedPackage, we skip it. This will happen
- // when scannedPackage is an update of an existing package. Without this check,
- // we will never be able to change the ABI of any package belonging to a shared
- // user, even if it's compatible with other packages.
- if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
- if (ps.primaryCpuAbiString == null) {
- continue;
- }
-
- final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
- if (requiredInstructionSet != null && !instructionSet.equals(requiredInstructionSet)) {
- // We have a mismatch between instruction sets (say arm vs arm64) warn about
- // this but there's not much we can do.
- String errorMessage = "Instruction set mismatch, "
- + ((requirer == null) ? "[caller]" : requirer)
- + " requires " + requiredInstructionSet + " whereas " + ps
- + " requires " + instructionSet;
- Slog.w(TAG, errorMessage);
- }
-
- if (requiredInstructionSet == null) {
- requiredInstructionSet = instructionSet;
- requirer = ps;
- }
- }
- }
-
- if (requiredInstructionSet != null) {
- String adjustedAbi;
- if (requirer != null) {
- // requirer != null implies that either scannedPackage was null or that scannedPackage
- // did not require an ABI, in which case we have to adjust scannedPackage to match
- // the ABI of the set (which is the same as requirer's ABI)
- adjustedAbi = requirer.primaryCpuAbiString;
- if (scannedPackage != null) {
- scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
- }
- } else {
- // requirer == null implies that we're updating all ABIs in the set to
- // match scannedPackage.
- adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
- }
-
- for (PackageSetting ps : packagesForUser) {
- if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
- if (ps.primaryCpuAbiString != null) {
- continue;
- }
-
- ps.primaryCpuAbiString = adjustedAbi;
- if (ps.pkg != null && ps.pkg.applicationInfo != null &&
- !TextUtils.equals(adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
- ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
- if (DEBUG_ABI_SELECTION) {
- Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
- + " (requirer="
- + (requirer != null ? requirer.pkg : "null")
- + ", scannedPackage="
- + (scannedPackage != null ? scannedPackage : "null")
- + ")");
- }
- if (changedAbiCodePath == null) {
- changedAbiCodePath = new ArrayList<>();
- }
- changedAbiCodePath.add(ps.codePathString);
- }
- }
- }
- }
- return changedAbiCodePath;
- }
-
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
synchronized (mPackages) {
mResolverReplaced = true;
@@ -12634,207 +12474,6 @@
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
}
- private static String calculateBundledApkRoot(final String codePathString) {
- final File codePath = new File(codePathString);
- final File codeRoot;
- if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
- codeRoot = Environment.getRootDirectory();
- } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
- codeRoot = Environment.getOemDirectory();
- } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
- codeRoot = Environment.getVendorDirectory();
- } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
- codeRoot = Environment.getOdmDirectory();
- } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
- codeRoot = Environment.getProductDirectory();
- } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
- codeRoot = Environment.getSystemExtDirectory();
- } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
- codeRoot = Environment.getOdmDirectory();
- } else {
- // Unrecognized code path; take its top real segment as the apk root:
- // e.g. /something/app/blah.apk => /something
- try {
- File f = codePath.getCanonicalFile();
- File parent = f.getParentFile(); // non-null because codePath is a file
- File tmp;
- while ((tmp = parent.getParentFile()) != null) {
- f = parent;
- parent = tmp;
- }
- codeRoot = f;
- Slog.w(TAG, "Unrecognized code path "
- + codePath + " - using " + codeRoot);
- } catch (IOException e) {
- // Can't canonicalize the code path -- shenanigans?
- Slog.w(TAG, "Can't canonicalize code path " + codePath);
- return Environment.getRootDirectory().getPath();
- }
- }
- return codeRoot.getPath();
- }
-
- /**
- * Derive and set the location of native libraries for the given package,
- * which varies depending on where and how the package was installed.
- */
- private static void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
- final ApplicationInfo info = pkg.applicationInfo;
- final String codePath = pkg.codePath;
- final File codeFile = new File(codePath);
- final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
-
- info.nativeLibraryRootDir = null;
- info.nativeLibraryRootRequiresIsa = false;
- info.nativeLibraryDir = null;
- info.secondaryNativeLibraryDir = null;
-
- if (isApkFile(codeFile)) {
- // Monolithic install
- if (bundledApp) {
- // If "/system/lib64/apkname" exists, assume that is the per-package
- // native library directory to use; otherwise use "/system/lib/apkname".
- final String apkRoot = calculateBundledApkRoot(info.sourceDir);
- final boolean is64Bit = VMRuntime.is64BitInstructionSet(
- getPrimaryInstructionSet(info));
-
- // This is a bundled system app so choose the path based on the ABI.
- // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
- // is just the default path.
- final String apkName = deriveCodePathName(codePath);
- final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
- info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
- apkName).getAbsolutePath();
-
- if (info.secondaryCpuAbi != null) {
- final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
- info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
- secondaryLibDir, apkName).getAbsolutePath();
- }
- } else {
- final String apkName = deriveCodePathName(codePath);
- info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
- .getAbsolutePath();
- }
-
- info.nativeLibraryRootRequiresIsa = false;
- info.nativeLibraryDir = info.nativeLibraryRootDir;
- } else {
- // Cluster install
- info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
- info.nativeLibraryRootRequiresIsa = true;
-
- info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
- getPrimaryInstructionSet(info)).getAbsolutePath();
-
- if (info.secondaryCpuAbi != null) {
- info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,
- VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();
- }
- }
- }
-
- /**
- * Calculate the abis and roots for a bundled app. These can uniquely
- * be determined from the contents of the system partition, i.e whether
- * it contains 64 or 32 bit shared libraries etc. We do not validate any
- * of this information, and instead assume that the system was built
- * sensibly.
- */
- private static void setBundledAppAbisAndRoots(PackageParser.Package pkg,
- PackageSetting pkgSetting) {
- final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
-
- // If "/system/lib64/apkname" exists, assume that is the per-package
- // native library directory to use; otherwise use "/system/lib/apkname".
- final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
- setBundledAppAbi(pkg, apkRoot, apkName);
- // pkgSetting might be null during rescan following uninstall of updates
- // to a bundled app, so accommodate that possibility. The settings in
- // that case will be established later from the parsed package.
- //
- // If the settings aren't null, sync them up with what we've just derived.
- // note that apkRoot isn't stored in the package settings.
- if (pkgSetting != null) {
- pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
- pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
- }
- }
-
- /**
- * Deduces the ABI of a bundled app and sets the relevant fields on the
- * parsed pkg object.
- *
- * @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}
- * under which system libraries are installed.
- * @param apkName the name of the installed package.
- */
- private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
- final File codeFile = new File(pkg.codePath);
-
- final boolean has64BitLibs;
- final boolean has32BitLibs;
- if (isApkFile(codeFile)) {
- // Monolithic install
- has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
- has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
- } else {
- // Cluster install
- final File rootDir = new File(codeFile, LIB_DIR_NAME);
- if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
- && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
- final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
- has64BitLibs = (new File(rootDir, isa)).exists();
- } else {
- has64BitLibs = false;
- }
- if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
- && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
- final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
- has32BitLibs = (new File(rootDir, isa)).exists();
- } else {
- has32BitLibs = false;
- }
- }
-
- if (has64BitLibs && !has32BitLibs) {
- // The package has 64 bit libs, but not 32 bit libs. Its primary
- // ABI should be 64 bit. We can safely assume here that the bundled
- // native libraries correspond to the most preferred ABI in the list.
-
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = null;
- } else if (has32BitLibs && !has64BitLibs) {
- // The package has 32 bit libs but not 64 bit libs. Its primary
- // ABI should be 32 bit.
-
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = null;
- } else if (has32BitLibs && has64BitLibs) {
- // The application has both 64 and 32 bit bundled libraries. We check
- // here that the app declares multiArch support, and warn if it doesn't.
- //
- // We will be lenient here and record both ABIs. The primary will be the
- // ABI that's higher on the list, i.e, a device that's configured to prefer
- // 64 bit apps will see a 64 bit primary ABI,
-
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
- Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
- }
-
- if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- } else {
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- }
- } else {
- pkg.applicationInfo.primaryCpuAbi = null;
- pkg.applicationInfo.secondaryCpuAbi = null;
- }
- }
-
private void killApplication(String pkgName, int appId, String reason) {
killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
}
@@ -13556,7 +13195,8 @@
// upgrade app from instant to full; we don't allow app downgrade
installed = true;
}
- setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+ setInstantAppForUser(
+ getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp);
}
if (installed) {
@@ -13604,8 +13244,8 @@
}
}
- static void setInstantAppForUser(PackageSetting pkgSetting, int userId,
- boolean instantApp, boolean fullApp) {
+ static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting,
+ int userId, boolean instantApp, boolean fullApp) {
// no state specified; do nothing
if (!instantApp && !fullApp) {
return;
@@ -13617,7 +13257,7 @@
pkgSetting.setInstantApp(false /*instantApp*/, userId);
}
} else {
- for (int currentUserId : sUserManager.getUserIds()) {
+ for (int currentUserId : userManager.getUserIds()) {
if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
} else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -15452,17 +15092,6 @@
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
mPendingEnableRollback.append(enableRollbackToken, this);
- final int[] installedUsers;
- synchronized (mPackages) {
- PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
- if (ps != null) {
- installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
- true);
- } else {
- installedUsers = new int[0];
- }
- }
-
Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
@@ -15471,9 +15100,6 @@
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
installFlags);
enableRollbackIntent.putExtra(
- PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
- installedUsers);
- enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
getRollbackUser().getIdentifier());
enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
@@ -15891,16 +15517,6 @@
}
}
- private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
- PackageManagerException {
- if (copyRet < 0) {
- if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
- copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
- throw new PackageManagerException(copyRet, message);
- }
- }
- }
-
/**
* Logic to handle movement of existing installed applications.
*/
@@ -16027,26 +15643,6 @@
return result;
}
- // Utility method that returns the relative package path with respect
- // to the installation directory. Like say for /data/data/com.test-1.apk
- // string com.test-1 is returned.
- static String deriveCodePathName(String codePath) {
- if (codePath == null) {
- return null;
- }
- final File codeFile = new File(codePath);
- final String name = codeFile.getName();
- if (codeFile.isDirectory()) {
- return name;
- } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
- final int lastDot = name.lastIndexOf('.');
- return name.substring(0, lastDot);
- } else {
- Slog.w(TAG, "Odd, " + codePath + " doesn't look like an APK");
- return null;
- }
- }
-
static class PackageInstalledInfo {
String name;
int uid;
@@ -16979,7 +16575,8 @@
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
- prepareResult = preparePackageLI(request.args, request.installResult);
+ prepareResult =
+ preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
request.installResult.setError(prepareFailure.error,
prepareFailure.getMessage());
@@ -17639,7 +17236,11 @@
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, abiOverride, extractNativeLibs);
+ final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
+ derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
+ pkg, abiOverride, extractNativeLibs);
+ derivedAbi.first.applyTo(pkg);
+ derivedAbi.second.applyTo(pkg);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -18168,10 +17769,6 @@
}
}
- private static boolean isMultiArch(ApplicationInfo info) {
- return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
- }
-
private static boolean isExternal(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
@@ -18180,7 +17777,7 @@
return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
- private static boolean isSystemApp(PackageParser.Package pkg) {
+ static boolean isSystemApp(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
@@ -24520,6 +24117,12 @@
public List<ResolveInfo> queryIntentActivities(
Intent intent, int flags, int filterCallingUid, int userId) {
final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
+ return queryIntentActivities(intent, resolvedType, flags, filterCallingUid, userId);
+ }
+
+ @Override
+ public List<ResolveInfo> queryIntentActivities(
+ Intent intent, String resolvedType, int flags, int filterCallingUid, int userId) {
return PackageManagerService.this
.queryIntentActivitiesInternal(intent, resolvedType, flags, filterCallingUid,
userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 58f262c..029673f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -270,7 +270,8 @@
updateAvailable = orig.updateAvailable;
}
- private PackageUserState modifyUserState(int userId) {
+ @VisibleForTesting
+ PackageUserState modifyUserState(int userId) {
PackageUserState state = mUserState.get(userId);
if (state == null) {
state = new PackageUserState();
@@ -463,6 +464,18 @@
state.harmfulAppWarning = harmfulAppWarning;
}
+ void setUserState(int userId, PackageUserState otherState) {
+ setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
+ otherState.stopped, otherState.notLaunched, otherState.hidden,
+ otherState.distractionFlags, otherState.suspended, otherState.suspendingPackage,
+ otherState.dialogInfo, otherState.suspendedAppExtras,
+ otherState.suspendedLauncherExtras, otherState.instantApp,
+ otherState.virtualPreload, otherState.lastDisableAppCaller,
+ otherState.enabledComponents, otherState.disabledComponents,
+ otherState.domainVerificationStatus, otherState.appLinkGeneration,
+ otherState.installReason, otherState.harmfulAppWarning);
+ }
+
ArraySet<String> getEnabledComponents(int userId) {
return readUserState(userId).enabledComponents;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 3bc2236..4ecfbfe 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3337,7 +3337,8 @@
int flags, ComponentName cn, String scheme, PatternMatcher ssp,
IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
final List<ResolveInfo> ri =
- pmInternal.queryIntentActivities(intent, flags, Binder.getCallingUid(), 0);
+ pmInternal.queryIntentActivities(
+ intent, intent.getType(), flags, Binder.getCallingUid(), 0);
if (PackageManagerService.DEBUG_PREFERRED) {
Log.d(TAG, "Queried " + intent + " results: " + ri);
}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 15dc6ae..0101366 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -8,6 +8,20 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm."
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
],
"imports": [
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
new file mode 100644
index 0000000..fe18fbf
--- /dev/null
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2016 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.recoverysystem;
+
+import android.content.Context;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.os.IRecoverySystem;
+import android.os.IRecoverySystemProgressListener;
+import android.os.PowerManager;
+import android.os.RecoverySystem;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+
+import libcore.io.IoUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * The recovery system service is responsible for coordinating recovery related
+ * functions on the device. It sets up (or clears) the bootloader control block
+ * (BCB), which will be read by the bootloader and the recovery image. It also
+ * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the
+ * /data partition so that it can be accessed under the recovery image.
+ */
+public class RecoverySystemService extends IRecoverySystem.Stub {
+ private static final String TAG = "RecoverySystemService";
+ private static final boolean DEBUG = false;
+
+ // The socket at /dev/socket/uncrypt to communicate with uncrypt.
+ private static final String UNCRYPT_SOCKET = "uncrypt";
+
+ // The init services that communicate with /system/bin/uncrypt.
+ @VisibleForTesting
+ static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
+ @VisibleForTesting
+ static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
+ @VisibleForTesting
+ static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+
+ private static final Object sRequestLock = new Object();
+
+ private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
+
+ private final Injector mInjector;
+ private final Context mContext;
+
+ static class Injector {
+ protected final Context mContext;
+
+ Injector(Context context) {
+ mContext = context;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public PowerManager getPowerManager() {
+ return (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ }
+
+ public String systemPropertiesGet(String key) {
+ return SystemProperties.get(key);
+ }
+
+ public void systemPropertiesSet(String key, String value) {
+ SystemProperties.set(key, value);
+ }
+
+ public boolean uncryptPackageFileDelete() {
+ return RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+ }
+
+ public String getUncryptPackageFileName() {
+ return RecoverySystem.UNCRYPT_PACKAGE_FILE.getName();
+ }
+
+ public FileWriter getUncryptPackageFileWriter() throws IOException {
+ return new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE);
+ }
+
+ public UncryptSocket connectService() {
+ UncryptSocket socket = new UncryptSocket();
+ if (!socket.connectService()) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ }
+
+ public void threadSleep(long millis) throws InterruptedException {
+ Thread.sleep(millis);
+ }
+ }
+
+ /**
+ * Handles the lifecycle events for the RecoverySystemService.
+ */
+ public static final class Lifecycle extends SystemService {
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ RecoverySystemService recoverySystemService = new RecoverySystemService(getContext());
+ publishBinderService(Context.RECOVERY_SERVICE, recoverySystemService);
+ }
+ }
+
+ private RecoverySystemService(Context context) {
+ this(new Injector(context));
+ }
+
+ @VisibleForTesting
+ RecoverySystemService(Injector injector) {
+ mInjector = injector;
+ mContext = injector.getContext();
+ }
+
+ @Override // Binder call
+ public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
+ if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
+
+ synchronized (sRequestLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+ if (!checkAndWaitForUncryptService()) {
+ Slog.e(TAG, "uncrypt service is unavailable.");
+ return false;
+ }
+
+ // Write the filename into uncrypt package file to be read by
+ // uncrypt.
+ mInjector.uncryptPackageFileDelete();
+
+ try (FileWriter uncryptFile = mInjector.getUncryptPackageFileWriter()) {
+ uncryptFile.write(filename + "\n");
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when writing \""
+ + mInjector.getUncryptPackageFileName() + "\":", e);
+ return false;
+ }
+
+ // Trigger uncrypt via init.
+ mInjector.systemPropertiesSet("ctl.start", "uncrypt");
+
+ // Connect to the uncrypt service socket.
+ UncryptSocket socket = mInjector.connectService();
+ if (socket == null) {
+ Slog.e(TAG, "Failed to connect to uncrypt socket");
+ return false;
+ }
+
+ // Read the status from the socket.
+ try {
+ int lastStatus = Integer.MIN_VALUE;
+ while (true) {
+ int status = socket.getPercentageUncrypted();
+ // Avoid flooding the log with the same message.
+ if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+ continue;
+ }
+ lastStatus = status;
+
+ if (status >= 0 && status <= 100) {
+ // Update status
+ Slog.i(TAG, "uncrypt read status: " + status);
+ if (listener != null) {
+ try {
+ listener.onProgress(status);
+ } catch (RemoteException ignored) {
+ Slog.w(TAG, "RemoteException when posting progress");
+ }
+ }
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt successfully finished.");
+ // Ack receipt of the final status code. uncrypt
+ // waits for the ack so the socket won't be
+ // destroyed before we receive the code.
+ socket.sendAck();
+ break;
+ }
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ // Ack receipt of the final status code. uncrypt waits
+ // for the ack so the socket won't be destroyed before
+ // we receive the code.
+ socket.sendAck();
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when reading status: ", e);
+ return false;
+ } finally {
+ socket.close();
+ }
+
+ return true;
+ }
+ }
+
+ @Override // Binder call
+ public boolean clearBcb() {
+ if (DEBUG) Slog.d(TAG, "clearBcb");
+ synchronized (sRequestLock) {
+ return setupOrClearBcb(false, null);
+ }
+ }
+
+ @Override // Binder call
+ public boolean setupBcb(String command) {
+ if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
+ synchronized (sRequestLock) {
+ return setupOrClearBcb(true, command);
+ }
+ }
+
+ @Override // Binder call
+ public void rebootRecoveryWithCommand(String command) {
+ if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
+ synchronized (sRequestLock) {
+ if (!setupOrClearBcb(true, command)) {
+ return;
+ }
+
+ // Having set up the BCB, go ahead and reboot.
+ PowerManager pm = mInjector.getPowerManager();
+ pm.reboot(PowerManager.REBOOT_RECOVERY);
+ }
+ }
+
+ /**
+ * Check if any of the init services is still running. If so, we cannot
+ * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
+ * it may break the socket communication since init creates / deletes
+ * the socket (/dev/socket/uncrypt) on service start / exit.
+ */
+ private boolean checkAndWaitForUncryptService() {
+ for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+ final String uncryptService = mInjector.systemPropertiesGet(INIT_SERVICE_UNCRYPT);
+ final String setupBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_SETUP_BCB);
+ final String clearBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_CLEAR_BCB);
+ final boolean busy = "running".equals(uncryptService)
+ || "running".equals(setupBcbService) || "running".equals(clearBcbService);
+ if (DEBUG) {
+ Slog.i(TAG, "retry: " + retry + " busy: " + busy
+ + " uncrypt: [" + uncryptService + "]"
+ + " setupBcb: [" + setupBcbService + "]"
+ + " clearBcb: [" + clearBcbService + "]");
+ }
+
+ if (!busy) {
+ return true;
+ }
+
+ try {
+ mInjector.threadSleep(1000);
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Interrupted:", e);
+ }
+ }
+
+ return false;
+ }
+
+ private boolean setupOrClearBcb(boolean isSetup, String command) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+ final boolean available = checkAndWaitForUncryptService();
+ if (!available) {
+ Slog.e(TAG, "uncrypt service is unavailable.");
+ return false;
+ }
+
+ if (isSetup) {
+ mInjector.systemPropertiesSet("ctl.start", "setup-bcb");
+ } else {
+ mInjector.systemPropertiesSet("ctl.start", "clear-bcb");
+ }
+
+ // Connect to the uncrypt service socket.
+ UncryptSocket socket = mInjector.connectService();
+ if (socket == null) {
+ Slog.e(TAG, "Failed to connect to uncrypt socket");
+ return false;
+ }
+
+ try {
+ // Send the BCB commands if it's to setup BCB.
+ if (isSetup) {
+ socket.sendCommand(command);
+ }
+
+ // Read the status from the socket.
+ int status = socket.getPercentageUncrypted();
+
+ // Ack receipt of the status code. uncrypt waits for the ack so
+ // the socket won't be destroyed before we receive the code.
+ socket.sendAck();
+
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear")
+ + " bcb successfully finished.");
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ return false;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when communicating with uncrypt:", e);
+ return false;
+ } finally {
+ socket.close();
+ }
+
+ return true;
+ }
+
+ /**
+ * Provides a wrapper for the low-level details of framing packets sent to the uncrypt
+ * socket.
+ */
+ public static class UncryptSocket {
+ private LocalSocket mLocalSocket;
+ private DataInputStream mInputStream;
+ private DataOutputStream mOutputStream;
+
+ /**
+ * Attempt to connect to the uncrypt service. Connection will be retried for up to
+ * {@link #SOCKET_CONNECTION_MAX_RETRY} times. If the connection is unsuccessful, the
+ * socket will be closed. If the connection is successful, the connection must be closed
+ * by the caller.
+ *
+ * @return true if connection was successful, false if unsuccessful
+ */
+ public boolean connectService() {
+ mLocalSocket = new LocalSocket();
+ boolean done = false;
+ // The uncrypt socket will be created by init upon receiving the
+ // service request. It may not be ready by this point. So we will
+ // keep retrying until success or reaching timeout.
+ for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+ try {
+ mLocalSocket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
+ LocalSocketAddress.Namespace.RESERVED));
+ done = true;
+ break;
+ } catch (IOException ignored) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Interrupted:", e);
+ }
+ }
+ }
+ if (!done) {
+ Slog.e(TAG, "Timed out connecting to uncrypt socket");
+ close();
+ return false;
+ }
+
+ try {
+ mInputStream = new DataInputStream(mLocalSocket.getInputStream());
+ mOutputStream = new DataOutputStream(mLocalSocket.getOutputStream());
+ } catch (IOException e) {
+ close();
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Sends a command to the uncrypt service.
+ *
+ * @param command command to send to the uncrypt service
+ * @throws IOException if the socket is closed or there was an error writing to the socket
+ */
+ public void sendCommand(String command) throws IOException {
+ if (mLocalSocket.isClosed()) {
+ throw new IOException("socket is closed");
+ }
+
+ byte[] cmdUtf8 = command.getBytes(StandardCharsets.UTF_8);
+ mOutputStream.writeInt(cmdUtf8.length);
+ mOutputStream.write(cmdUtf8, 0, cmdUtf8.length);
+ }
+
+ /**
+ * Reads the status from the uncrypt service which is usually represented as a percentage.
+ * @return an integer representing the percentage completed
+ * @throws IOException if the socket was closed or there was an error reading the socket
+ */
+ public int getPercentageUncrypted() throws IOException {
+ if (mLocalSocket.isClosed()) {
+ throw new IOException("socket is closed");
+ }
+
+ return mInputStream.readInt();
+ }
+
+ /**
+ * Sends a confirmation to the uncrypt service.
+ * @throws IOException if the socket was closed or there was an error writing to the socket
+ */
+ public void sendAck() throws IOException {
+ if (mLocalSocket.isClosed()) {
+ throw new IOException("socket is closed");
+ }
+
+ mOutputStream.writeInt(0);
+ }
+
+ /**
+ * Closes the socket and all underlying data streams.
+ */
+ public void close() {
+ IoUtils.closeQuietly(mInputStream);
+ IoUtils.closeQuietly(mOutputStream);
+ IoUtils.closeQuietly(mLocalSocket);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index 56e1d08..cae09ea3 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -20,7 +20,7 @@
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.os.storage.StorageManager;
import android.util.IntArray;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseLongArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -52,17 +52,18 @@
}
/**
- * Creates an app data snapshot for a specified {@code packageRollbackInfo}. Updates said {@code
- * packageRollbackInfo} with the inodes of the CE user data snapshot folders.
+ * Creates an app data snapshot for a specified {@code packageRollbackInfo} and the specified
+ * {@code userIds}. Updates said {@code packageRollbackInfo} with the inodes of the CE user data
+ * snapshot folders.
*/
- public void snapshotAppData(int snapshotId, PackageRollbackInfo packageRollbackInfo) {
- final int[] installedUsers = packageRollbackInfo.getInstalledUsers().toArray();
- for (int user : installedUsers) {
+ public void snapshotAppData(
+ int snapshotId, PackageRollbackInfo packageRollbackInfo, int[] userIds) {
+ for (int user : userIds) {
final int storageFlags;
if (isUserCredentialLocked(user)) {
// We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
// across app user data until the user unlocks their device.
- Log.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
+ Slog.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
storageFlags = Installer.FLAG_STORAGE_DE;
packageRollbackInfo.addPendingBackup(user);
} else {
@@ -76,10 +77,11 @@
packageRollbackInfo.putCeSnapshotInode(user, ceSnapshotInode);
}
} catch (InstallerException ie) {
- Log.e(TAG, "Unable to create app data snapshot for: "
+ Slog.e(TAG, "Unable to create app data snapshot for: "
+ packageRollbackInfo.getPackageName() + ", userId: " + user, ie);
}
}
+ packageRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
}
/**
@@ -96,14 +98,14 @@
final IntArray pendingBackups = packageRollbackInfo.getPendingBackups();
final List<RestoreInfo> pendingRestores = packageRollbackInfo.getPendingRestores();
- boolean changedRollbackData = false;
+ boolean changedRollback = false;
// If we still have a userdata backup pending for this user, it implies that the user
// hasn't unlocked their device between the point of backup and the point of restore,
// so the data cannot have changed. We simply skip restoring CE data in this case.
if (pendingBackups != null && pendingBackups.indexOf(userId) != -1) {
pendingBackups.remove(pendingBackups.indexOf(userId));
- changedRollbackData = true;
+ changedRollback = true;
} else {
// There's no pending CE backup for this user, which means that we successfully
// managed to backup data for the user, which means we seek to restore it
@@ -111,7 +113,7 @@
// We've encountered a user that hasn't unlocked on a FBE device, so we can't
// copy across app user data until the user unlocks their device.
pendingRestores.add(new RestoreInfo(userId, appId, seInfo));
- changedRollbackData = true;
+ changedRollback = true;
} else {
// This user has unlocked, we can proceed to restore both CE and DE data.
storageFlags = storageFlags | Installer.FLAG_STORAGE_CE;
@@ -122,11 +124,11 @@
mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId, seInfo,
userId, rollbackId, storageFlags);
} catch (InstallerException ie) {
- Log.e(TAG, "Unable to restore app data snapshot: "
+ Slog.e(TAG, "Unable to restore app data snapshot: "
+ packageRollbackInfo.getPackageName(), ie);
}
- return changedRollbackData;
+ return changedRollback;
}
/**
@@ -148,7 +150,7 @@
ceSnapshotInodes.delete(user);
}
} catch (InstallerException ie) {
- Log.e(TAG, "Unable to delete app data snapshot for "
+ Slog.e(TAG, "Unable to delete app data snapshot for "
+ packageRollbackInfo.getPackageName(), ie);
}
}
@@ -158,29 +160,29 @@
* Packages pending backup for the given user are added to {@code pendingBackupPackages} along
* with their corresponding {@code PackageRollbackInfo}.
*
- * @return the list of {@code RollbackData} that has pending backups. Note that some of the
+ * @return the list of rollbacks that have pending backups. Note that some of the
* backups won't be performed, because they might be counteracted by pending restores.
*/
- private static List<RollbackData> computePendingBackups(int userId,
+ private static List<Rollback> computePendingBackups(int userId,
Map<String, PackageRollbackInfo> pendingBackupPackages,
- List<RollbackData> rollbacks) {
- List<RollbackData> rd = new ArrayList<>();
+ List<Rollback> rollbacks) {
+ List<Rollback> rollbacksWithPendingBackups = new ArrayList<>();
- for (RollbackData data : rollbacks) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : rollbacks) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final IntArray pendingBackupUsers = info.getPendingBackups();
if (pendingBackupUsers != null) {
final int idx = pendingBackupUsers.indexOf(userId);
if (idx != -1) {
pendingBackupPackages.put(info.getPackageName(), info);
- if (rd.indexOf(data) == -1) {
- rd.add(data);
+ if (rollbacksWithPendingBackups.indexOf(rollback) == -1) {
+ rollbacksWithPendingBackups.add(rollback);
}
}
}
}
}
- return rd;
+ return rollbacksWithPendingBackups;
}
/**
@@ -188,45 +190,45 @@
* Packages pending restore are added to {@code pendingRestores} along with their corresponding
* {@code PackageRollbackInfo}.
*
- * @return the list of {@code RollbackData} that has pending restores. Note that some of the
+ * @return the list of rollbacks that have pending restores. Note that some of the
* restores won't be performed, because they might be counteracted by pending backups.
*/
- private static List<RollbackData> computePendingRestores(int userId,
+ private static List<Rollback> computePendingRestores(int userId,
Map<String, PackageRollbackInfo> pendingRestorePackages,
- List<RollbackData> rollbacks) {
- List<RollbackData> rd = new ArrayList<>();
+ List<Rollback> rollbacks) {
+ List<Rollback> rollbacksWithPendingRestores = new ArrayList<>();
- for (RollbackData data : rollbacks) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : rollbacks) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final RestoreInfo ri = info.getRestoreInfo(userId);
if (ri != null) {
pendingRestorePackages.put(info.getPackageName(), info);
- if (rd.indexOf(data) == -1) {
- rd.add(data);
+ if (rollbacksWithPendingRestores.indexOf(rollback) == -1) {
+ rollbacksWithPendingRestores.add(rollback);
}
}
}
}
- return rd;
+ return rollbacksWithPendingRestores;
}
/**
- * Commits the list of pending backups and restores for a given {@code userId}. For the pending
- * backups updates corresponding {@code changedRollbackData} with a mapping from {@code userId}
- * to a inode of theirs CE user data snapshot.
+ * Commits the list of pending backups and restores for a given {@code userId}. For rollbacks
+ * with pending backups, updates the {@code Rollback} instance with a mapping from
+ * {@code userId} to inode of the CE user data snapshot.
*
- * @return the set of {@code RollbackData} that have been changed and should be stored on disk.
+ * @return the set of rollbacks with changes that should be stored on disk.
*/
- public Set<RollbackData> commitPendingBackupAndRestoreForUser(int userId,
- List<RollbackData> rollbacks) {
+ public Set<Rollback> commitPendingBackupAndRestoreForUser(int userId,
+ List<Rollback> rollbacks) {
final Map<String, PackageRollbackInfo> pendingBackupPackages = new HashMap<>();
- final List<RollbackData> pendingBackups = computePendingBackups(userId,
+ final List<Rollback> pendingBackups = computePendingBackups(userId,
pendingBackupPackages, rollbacks);
final Map<String, PackageRollbackInfo> pendingRestorePackages = new HashMap<>();
- final List<RollbackData> pendingRestores = computePendingRestores(userId,
+ final List<Rollback> pendingRestores = computePendingRestores(userId,
pendingRestorePackages, rollbacks);
// First remove unnecessary backups, i.e. when user did not unlock their phone between the
@@ -246,18 +248,19 @@
}
if (!pendingBackupPackages.isEmpty()) {
- for (RollbackData data : pendingBackups) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : pendingBackups) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final IntArray pendingBackupUsers = info.getPendingBackups();
final int idx = pendingBackupUsers.indexOf(userId);
if (idx != -1) {
try {
long ceSnapshotInode = mInstaller.snapshotAppData(info.getPackageName(),
- userId, data.info.getRollbackId(), Installer.FLAG_STORAGE_CE);
+ userId, rollback.info.getRollbackId(),
+ Installer.FLAG_STORAGE_CE);
info.putCeSnapshotInode(userId, ceSnapshotInode);
pendingBackupUsers.remove(idx);
} catch (InstallerException ie) {
- Log.e(TAG,
+ Slog.e(TAG,
"Unable to create app data snapshot for: "
+ info.getPackageName() + ", userId: " + userId, ie);
}
@@ -267,17 +270,17 @@
}
if (!pendingRestorePackages.isEmpty()) {
- for (RollbackData data : pendingRestores) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (Rollback rollback : pendingRestores) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
final RestoreInfo ri = info.getRestoreInfo(userId);
if (ri != null) {
try {
mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId,
- ri.seInfo, userId, data.info.getRollbackId(),
+ ri.seInfo, userId, rollback.info.getRollbackId(),
Installer.FLAG_STORAGE_CE);
info.removeRestoreInfo(ri);
} catch (InstallerException ie) {
- Log.e(TAG, "Unable to restore app data snapshot for: "
+ Slog.e(TAG, "Unable to restore app data snapshot for: "
+ info.getPackageName(), ie);
}
}
@@ -285,7 +288,7 @@
}
}
- final Set<RollbackData> changed = new HashSet<>(pendingBackups);
+ final Set<Rollback> changed = new HashSet<>(pendingBackups);
changed.addAll(pendingRestores);
return changed;
}
diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/Rollback.java
similarity index 85%
rename from services/core/java/com/android/server/rollback/RollbackData.java
rename to services/core/java/com/android/server/rollback/Rollback.java
index b37e268..0d5746b 100644
--- a/services/core/java/com/android/server/rollback/RollbackData.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -32,7 +32,7 @@
* Information about a rollback available for a set of atomically installed
* packages.
*/
-class RollbackData {
+class Rollback {
@IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = {
ROLLBACK_STATE_ENABLING,
ROLLBACK_STATE_AVAILABLE,
@@ -102,13 +102,13 @@
public boolean restoreUserDataInProgress = false;
/**
- * Constructs a new, empty RollbackData instance.
+ * Constructs a new, empty Rollback instance.
*
* @param rollbackId the id of the rollback.
* @param backupDir the directory where the rollback data is stored.
* @param stagedSessionId the session id if this is a staged rollback, -1 otherwise.
*/
- RollbackData(int rollbackId, File backupDir, int stagedSessionId) {
+ Rollback(int rollbackId, File backupDir, int stagedSessionId) {
this.info = new RollbackInfo(rollbackId,
/* packages */ new ArrayList<>(),
/* isStaged */ stagedSessionId != -1,
@@ -121,9 +121,9 @@
}
/**
- * Constructs a RollbackData instance with full rollback data information.
+ * Constructs a pre-populated Rollback instance.
*/
- RollbackData(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
+ Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
@RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress) {
this.info = info;
this.backupDir = backupDir;
@@ -143,9 +143,9 @@
static String rollbackStateToString(@RollbackState int state) {
switch (state) {
- case RollbackData.ROLLBACK_STATE_ENABLING: return "enabling";
- case RollbackData.ROLLBACK_STATE_AVAILABLE: return "available";
- case RollbackData.ROLLBACK_STATE_COMMITTED: return "committed";
+ case Rollback.ROLLBACK_STATE_ENABLING: return "enabling";
+ case Rollback.ROLLBACK_STATE_AVAILABLE: return "available";
+ case Rollback.ROLLBACK_STATE_COMMITTED: return "committed";
}
throw new AssertionError("Invalid rollback state: " + state);
}
@@ -153,9 +153,9 @@
static @RollbackState int rollbackStateFromString(String state)
throws ParseException {
switch (state) {
- case "enabling": return RollbackData.ROLLBACK_STATE_ENABLING;
- case "available": return RollbackData.ROLLBACK_STATE_AVAILABLE;
- case "committed": return RollbackData.ROLLBACK_STATE_COMMITTED;
+ case "enabling": return Rollback.ROLLBACK_STATE_ENABLING;
+ case "available": return Rollback.ROLLBACK_STATE_AVAILABLE;
+ case "committed": return Rollback.ROLLBACK_STATE_COMMITTED;
}
throw new ParseException("Invalid rollback state: " + state, 0);
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index e107c9a..42f3e2fd 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -45,14 +45,13 @@
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.UserHandle; // duped to avoid merge conflict
-import android.os.UserManager; // out of order to avoid merge conflict
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.IntArray;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
@@ -76,6 +75,7 @@
import java.util.List;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -110,14 +110,13 @@
@GuardedBy("mLock")
private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray();
- // Package rollback data for rollbacks we are in the process of enabling.
+ // Rollbacks we are in the process of enabling.
@GuardedBy("mLock")
private final Set<NewRollback> mNewRollbacks = new ArraySet<>();
// The list of all rollbacks, including available and committed rollbacks.
- // This list is null until the rollback data has been loaded.
@GuardedBy("mLock")
- private List<RollbackData> mRollbacks;
+ private final List<Rollback> mRollbacks;
private final RollbackStore mRollbackStore;
@@ -128,7 +127,7 @@
private final AppDataRollbackHelper mAppDataRollbackHelper;
// This field stores the difference in Millis between the uptime (millis since device
- // has booted) and current time (device wall clock) - it's used to update rollback data
+ // has booted) and current time (device wall clock) - it's used to update rollback
// timestamps when the time is changed, by the user or by change of timezone.
// No need for guarding with lock because value is only accessed in handler thread.
private long mRelativeBootTime = calculateRelativeBootTime();
@@ -139,29 +138,25 @@
// SystemService#onStart.
mInstaller = new Installer(mContext);
mInstaller.onStart();
- mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
- mHandlerThread.start();
-
- // Monitor the handler thread
- Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
- // Kick off loading of the rollback data from strorage in a background
- // thread.
- // TODO: Consider loading the rollback data directly here instead, to
- // avoid the need to call ensureRollbackDataLoaded every time before
- // accessing the rollback data?
- // TODO: Test that this kicks off initial scheduling of rollback
- // expiration.
- getHandler().post(() -> ensureRollbackDataLoaded());
+ // Load rollback data from device storage.
+ synchronized (mLock) {
+ mRollbacks = mRollbackStore.loadRollbacks();
+ for (Rollback rollback : mRollbacks) {
+ mAllocatedRollbackIds.put(rollback.info.getRollbackId(), true);
+ }
+ }
- // TODO: Make sure to register these call backs when a new user is
- // added too.
- SessionCallback sessionCallback = new SessionCallback();
+ // Kick off and start monitoring the handler thread.
+ mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
+ mHandlerThread.start();
+ Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
+
for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
registerUserCallbacks(userInfo.getUserHandle());
}
@@ -171,7 +166,7 @@
try {
enableRollbackFilter.addDataType("application/vnd.android.package-archive");
} catch (IntentFilter.MalformedMimeTypeException e) {
- Log.e(TAG, "addDataType", e);
+ Slog.e(TAG, "addDataType", e);
}
mContext.registerReceiver(new BroadcastReceiver() {
@@ -182,16 +177,14 @@
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
int installFlags = intent.getIntExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
- int[] installedUsers = intent.getIntArrayExtra(
- PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS);
int user = intent.getIntExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, 0);
File newPackageCodePath = new File(intent.getData().getPath());
getHandler().post(() -> {
- boolean success = enableRollback(installFlags, newPackageCodePath,
- installedUsers, user, token);
+ boolean success =
+ enableRollback(installFlags, newPackageCodePath, user, token);
int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
if (!success) {
ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
@@ -251,13 +244,10 @@
private void registerUserCallbacks(UserHandle user) {
Context context = getContextAsUser(user);
if (context == null) {
- Log.e(TAG, "Unable to register user callbacks for user " + user);
+ Slog.e(TAG, "Unable to register user callbacks for user " + user);
return;
}
- // TODO: Reuse the same SessionCallback and broadcast receiver
- // instances, rather than creating new instances for each user.
-
context.getPackageManager().getPackageInstaller()
.registerSessionCallback(new SessionCallback(), getHandler());
@@ -281,44 +271,15 @@
}, filter, null, getHandler());
}
- /**
- * This method posts a blocking call to the handler thread, so it should not be called from
- * that same thread.
- * @throws {@link IllegalStateException} if called from {@link #mHandlerThread}
- */
@Override
public ParceledListSlice getAvailableRollbacks() {
enforceManageRollbacks("getAvailableRollbacks");
- if (Thread.currentThread().equals(mHandlerThread)) {
- Log.wtf(TAG, "Calling getAvailableRollbacks from mHandlerThread "
- + "causes a deadlock");
- throw new IllegalStateException("Cannot call RollbackManager#getAvailableRollbacks "
- + "from the handler thread!");
- }
-
- // Wait for the handler thread to get the list of available rollbacks
- // to get the most up-to-date results. This is intended to reduce test
- // flakiness when checking available rollbacks immediately after
- // installing a package with rollback enabled.
- final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
- getHandler().post(() -> result.offer(true));
-
- try {
- result.take();
- } catch (InterruptedException ie) {
- // We may not get the most up-to-date information, but whatever we
- // can get now is better than nothing, so log but otherwise ignore
- // the exception.
- Log.w(TAG, "Interrupted while waiting for handler thread in getAvailableRollbacks");
- }
-
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE) {
- rollbacks.add(data.info);
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE) {
+ rollbacks.add(rollback.info);
}
}
return new ParceledListSlice<>(rollbacks);
@@ -326,16 +287,15 @@
}
@Override
- public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
+ public ParceledListSlice<RollbackInfo> getRecentlyCommittedRollbacks() {
enforceManageRollbacks("getRecentlyCommittedRollbacks");
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) {
- rollbacks.add(data.info);
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) {
+ rollbacks.add(rollback.info);
}
}
return new ParceledListSlice<>(rollbacks);
@@ -345,7 +305,7 @@
@Override
public void commitRollback(int rollbackId, ParceledListSlice causePackages,
String callerPackageName, IntentSender statusReceiver) {
- enforceManageRollbacks("executeRollback");
+ enforceManageRollbacks("commitRollback");
final int callingUid = Binder.getCallingUid();
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -365,13 +325,11 @@
final long timeDifference = mRelativeBootTime - oldRelativeBootTime;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
-
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
- data.timestamp = data.timestamp.plusMillis(timeDifference);
- saveRollbackData(data);
+ Rollback rollback = iter.next();
+ rollback.timestamp = rollback.timestamp.plusMillis(timeDifference);
+ saveRollback(rollback);
}
}
}
@@ -393,10 +351,10 @@
*/
private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
String callerPackageName, IntentSender statusReceiver) {
- Log.i(TAG, "Initiating rollback");
+ Slog.i(TAG, "Initiating rollback");
- RollbackData data = getRollbackForId(rollbackId);
- if (data == null || data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) {
+ Rollback rollback = getRollbackForId(rollbackId);
+ if (rollback == null || rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) {
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
"Rollback unavailable");
return;
@@ -404,7 +362,7 @@
// Get a context for the caller to use to install the downgraded
// version of the package.
- Context context = null;
+ final Context context;
try {
context = mContext.createPackageContext(callerPackageName, 0);
} catch (PackageManager.NameNotFoundException e) {
@@ -420,14 +378,14 @@
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
parentParams.setRequestDowngrade(true);
parentParams.setMultiPackage();
- if (data.isStaged()) {
+ if (rollback.isStaged()) {
parentParams.setStaged();
}
int parentSessionId = packageInstaller.createSession(parentParams);
PackageInstaller.Session parentSession = packageInstaller.openSession(parentSessionId);
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
// TODO: We can't get the installerPackageName for apex
@@ -442,7 +400,7 @@
params.setRequestDowngrade(true);
params.setRequiredInstalledVersionCode(
info.getVersionRolledBackFrom().getLongVersionCode());
- if (data.isStaged()) {
+ if (rollback.isStaged()) {
params.setStaged();
}
if (info.isApex()) {
@@ -450,9 +408,8 @@
}
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-
File[] packageCodePaths = RollbackStore.getPackageCodePaths(
- data, info.getPackageName());
+ rollback, info.getPackageName());
if (packageCodePaths == null) {
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
"Backup copy of package inaccessible");
@@ -493,8 +450,8 @@
// TODO: Could this cause a rollback to be
// resurrected if it should otherwise have
// expired by now?
- data.state = RollbackData.ROLLBACK_STATE_AVAILABLE;
- data.restoreUserDataInProgress = false;
+ rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE;
+ rollback.restoreUserDataInProgress = false;
}
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL,
"Rollback downgrade install failed: "
@@ -504,35 +461,37 @@
}
synchronized (mLock) {
- if (!data.isStaged()) {
+ if (!rollback.isStaged()) {
// All calls to restoreUserData should have
// completed by now for a non-staged install.
- data.restoreUserDataInProgress = false;
+ rollback.restoreUserDataInProgress = false;
}
- data.info.setCommittedSessionId(parentSessionId);
- data.info.getCausePackages().addAll(causePackages);
+ rollback.info.setCommittedSessionId(parentSessionId);
+ rollback.info.getCausePackages().addAll(causePackages);
}
- mRollbackStore.deletePackageCodePaths(data);
- saveRollbackData(data);
+ mRollbackStore.deletePackageCodePaths(rollback);
+ saveRollback(rollback);
sendSuccess(statusReceiver);
Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
- mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM,
- Manifest.permission.MANAGE_ROLLBACKS);
+ for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
+ mContext.sendBroadcastAsUser(broadcast, userInfo.getUserHandle(),
+ Manifest.permission.MANAGE_ROLLBACKS);
+ }
});
}
);
synchronized (mLock) {
- data.state = RollbackData.ROLLBACK_STATE_COMMITTED;
- data.restoreUserDataInProgress = true;
+ rollback.state = Rollback.ROLLBACK_STATE_COMMITTED;
+ rollback.restoreUserDataInProgress = true;
}
parentSession.commit(receiver.getIntentSender());
} catch (IOException e) {
- Log.e(TAG, "Rollback failed", e);
+ Slog.e(TAG, "Rollback failed", e);
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
"IOException: " + e.toString());
return;
@@ -545,13 +504,21 @@
Manifest.permission.TEST_MANAGE_ROLLBACKS,
"reloadPersistedData");
- synchronized (mLock) {
- mRollbacks = null;
- }
+ CountDownLatch latch = new CountDownLatch(1);
getHandler().post(() -> {
updateRollbackLifetimeDurationInMillis();
- ensureRollbackDataLoaded();
+ synchronized (mLock) {
+ mRollbacks.clear();
+ mRollbacks.addAll(mRollbackStore.loadRollbacks());
+ }
+ latch.countDown();
});
+
+ try {
+ latch.await();
+ } catch (InterruptedException ie) {
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
+ }
}
@Override
@@ -560,14 +527,21 @@
Manifest.permission.TEST_MANAGE_ROLLBACKS,
"expireRollbackForPackage");
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ Rollback rollback = iter.next();
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)) {
iter.remove();
- deleteRollback(data);
+ deleteRollback(rollback);
+ break;
+ }
+ }
+ }
+ for (NewRollback newRollback : mNewRollbacks) {
+ for (PackageRollbackInfo info : newRollback.rollback.info.getPackages()) {
+ if (info.getPackageName().equals(packageName)) {
+ newRollback.isCancelled = true;
break;
}
}
@@ -575,18 +549,32 @@
}
}
+ @Override
+ public void blockRollbackManager(long millis) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
+ "blockRollbackManager");
+ getHandler().post(() -> {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
+ }
+ });
+ }
+
void onUnlockUser(int userId) {
getHandler().post(() -> {
- final List<RollbackData> rollbacks;
+ final List<Rollback> rollbacks;
synchronized (mLock) {
rollbacks = new ArrayList<>(mRollbacks);
}
- final Set<RollbackData> changed =
+ final Set<Rollback> changed =
mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId, rollbacks);
- for (RollbackData rd : changed) {
- saveRollbackData(rd);
+ for (Rollback rollback : changed) {
+ saveRollback(rollback);
}
});
}
@@ -609,20 +597,19 @@
getHandler().post(() -> {
// Check to see if any rollback-enabled staged sessions or staged
// rollback sessions been applied.
- List<RollbackData> enabling = new ArrayList<>();
- List<RollbackData> restoreInProgress = new ArrayList<>();
+ List<Rollback> enabling = new ArrayList<>();
+ List<Rollback> restoreInProgress = new ArrayList<>();
Set<String> apexPackageNames = new HashSet<>();
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
- for (RollbackData data : mRollbacks) {
- if (data.isStaged()) {
- if (data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
- enabling.add(data);
- } else if (data.restoreUserDataInProgress) {
- restoreInProgress.add(data);
+ for (Rollback rollback : mRollbacks) {
+ if (rollback.isStaged()) {
+ if (rollback.state == Rollback.ROLLBACK_STATE_ENABLING) {
+ enabling.add(rollback);
+ } else if (rollback.restoreUserDataInProgress) {
+ restoreInProgress.add(rollback);
}
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.isApex()) {
apexPackageNames.add(info.getPackageName());
}
@@ -631,35 +618,32 @@
}
}
- for (RollbackData data : enabling) {
+ for (Rollback rollback : enabling) {
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo session = installer.getSessionInfo(
- data.stagedSessionId);
- // TODO: What if session is null?
- if (session != null) {
- if (session.isStagedSessionApplied()) {
- makeRollbackAvailable(data);
- } else if (session.isStagedSessionFailed()) {
- // TODO: Do we need to remove this from
- // mRollbacks, or is it okay to leave as
- // unavailable until the next reboot when it will go
- // away on its own?
- deleteRollback(data);
- }
+ rollback.stagedSessionId);
+ if (session == null || session.isStagedSessionFailed()) {
+ // TODO: Do we need to remove this from
+ // mRollbacks, or is it okay to leave as
+ // unavailable until the next reboot when it will go
+ // away on its own?
+ deleteRollback(rollback);
+ } else if (session.isStagedSessionApplied()) {
+ makeRollbackAvailable(rollback);
}
}
- for (RollbackData data : restoreInProgress) {
+ for (Rollback rollback : restoreInProgress) {
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo session = installer.getSessionInfo(
- data.stagedSessionId);
+ rollback.stagedSessionId);
// TODO: What if session is null?
if (session != null) {
if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) {
synchronized (mLock) {
- data.restoreUserDataInProgress = false;
+ rollback.restoreUserDataInProgress = false;
}
- saveRollbackData(data);
+ saveRollback(rollback);
}
}
}
@@ -676,42 +660,6 @@
}
/**
- * Load rollback data from storage if it has not already been loaded.
- * After calling this funciton, mAvailableRollbacks and
- * mRecentlyExecutedRollbacks will be non-null.
- */
- private void ensureRollbackDataLoaded() {
- synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
- }
- }
-
- /**
- * Load rollback data from storage if it has not already been loaded.
- * After calling this function, mRollbacks will be non-null.
- */
- @GuardedBy("mLock")
- private void ensureRollbackDataLoadedLocked() {
- if (mRollbacks == null) {
- loadAllRollbackDataLocked();
- }
- }
-
- /**
- * Load all rollback data from storage.
- * Note: We do potentially heavy IO here while holding mLock, because we
- * have to have the rollback data loaded before we can do anything else
- * meaningful.
- */
- @GuardedBy("mLock")
- private void loadAllRollbackDataLocked() {
- mRollbacks = mRollbackStore.loadAllRollbackData();
- for (RollbackData data : mRollbacks) {
- mAllocatedRollbackIds.put(data.info.getRollbackId(), true);
- }
- }
-
- /**
* Called when a package has been replaced with a different version.
* Removes all backups for the package not matching the currently
* installed package version.
@@ -722,20 +670,19 @@
VersionedPackage installedVersion = getInstalledPackageVersion(packageName);
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
+ Rollback rollback = iter.next();
// TODO: Should we remove rollbacks in the ENABLING state here?
- if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE
- || data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE
+ || rollback.state == Rollback.ROLLBACK_STATE_ENABLING) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)
&& !packageVersionsEqual(
info.getVersionRolledBackFrom(),
installedVersion)) {
iter.remove();
- deleteRollback(data);
+ deleteRollback(rollback);
break;
}
}
@@ -761,7 +708,7 @@
*/
private void sendFailure(IntentSender statusReceiver, @RollbackManager.Status int status,
String message) {
- Log.e(TAG, message);
+ Slog.e(TAG, message);
try {
final Intent fillIn = new Intent();
fillIn.putExtra(RollbackManager.EXTRA_STATUS, status);
@@ -791,19 +738,18 @@
Instant now = Instant.now();
Instant oldest = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
-
- Iterator<RollbackData> iter = mRollbacks.iterator();
+ Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
- RollbackData data = iter.next();
- if (data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) {
+ Rollback rollback = iter.next();
+ if (rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) {
continue;
}
- if (!now.isBefore(data.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
+ if (!now.isBefore(
+ rollback.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
iter.remove();
- deleteRollback(data);
- } else if (oldest == null || oldest.isAfter(data.timestamp)) {
- oldest = data.timestamp;
+ deleteRollback(rollback);
+ } else if (oldest == null || oldest.isAfter(rollback.timestamp)) {
+ oldest = rollback.timestamp;
}
}
}
@@ -858,13 +804,12 @@
*
* @param installFlags information about what is being installed.
* @param newPackageCodePath path to the package about to be installed.
- * @param installedUsers the set of users for which a given package is installed.
* @param user the user that owns the install session to enable rollback on.
* @param token the distinct rollback token sent by package manager.
* @return true if enabling the rollback succeeds, false otherwise.
*/
- private boolean enableRollback(int installFlags, File newPackageCodePath,
- int[] installedUsers, @UserIdInt int user, int token) {
+ private boolean enableRollback(
+ int installFlags, File newPackageCodePath, @UserIdInt int user, int token) {
// Find the session id associated with this install.
// TODO: It would be nice if package manager or package installer told
@@ -876,7 +821,7 @@
// session.
final Context context = getContextAsUser(UserHandle.of(user));
if (context == null) {
- Log.e(TAG, "Unable to create context for install session user.");
+ Slog.e(TAG, "Unable to create context for install session user.");
return false;
}
@@ -903,45 +848,21 @@
}
if (parentSession == null || packageSession == null) {
- Log.e(TAG, "Unable to find session for enabled rollback.");
+ Slog.e(TAG, "Unable to find session for enabled rollback.");
return false;
}
// Check to see if this is the apk session for a staged session with
// rollback enabled.
- // TODO: This check could be made more efficient.
- RollbackData rd = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.apkSessionId == parentSession.getSessionId()) {
- rd = data;
- break;
- }
- }
- }
-
- if (rd != null) {
- // This is the apk session for a staged session. We do not need to create a new rollback
- // for this session.
- PackageParser.PackageLite newPackage = null;
- try {
- newPackage = PackageParser.parsePackageLite(
- new File(packageSession.resolvedBaseCodePath), 0);
- } catch (PackageParser.PackageParserException e) {
- Log.e(TAG, "Unable to parse new package", e);
- return false;
- }
- String packageName = newPackage.packageName;
- for (PackageRollbackInfo info : rd.info.getPackages()) {
- if (info.getPackageName().equals(packageName)) {
- info.getInstalledUsers().addAll(IntArray.wrap(installedUsers));
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.apkSessionId == parentSession.getSessionId()) {
+ // This is the apk session for a staged session with rollback enabled. We do not
+ // need to create a new rollback for this session.
return true;
}
}
- Log.e(TAG, "Unable to find package in apk session");
- return false;
}
NewRollback newRollback;
@@ -957,7 +878,7 @@
}
newRollback.addToken(token);
- return enableRollbackForPackageSession(newRollback.data, packageSession, installedUsers);
+ return enableRollbackForPackageSession(newRollback.rollback, packageSession);
}
/**
@@ -967,21 +888,21 @@
*
* @return true on success, false on failure.
*/
- private boolean enableRollbackForPackageSession(RollbackData data,
- PackageInstaller.SessionInfo session, @NonNull int[] installedUsers) {
+ private boolean enableRollbackForPackageSession(Rollback rollback,
+ PackageInstaller.SessionInfo session) {
// TODO: Don't attempt to enable rollback for split installs.
final int installFlags = session.installFlags;
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
- Log.e(TAG, "Rollback is not enabled.");
+ Slog.e(TAG, "Rollback is not enabled.");
return false;
}
if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Log.e(TAG, "Rollbacks not supported for instant app install");
+ Slog.e(TAG, "Rollbacks not supported for instant app install");
return false;
}
if (session.resolvedBaseCodePath == null) {
- Log.e(TAG, "Session code path has not been resolved.");
+ Slog.e(TAG, "Session code path has not been resolved.");
return false;
}
@@ -990,17 +911,17 @@
try {
newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0);
} catch (PackageParser.PackageParserException e) {
- Log.e(TAG, "Unable to parse new package", e);
+ Slog.e(TAG, "Unable to parse new package", e);
return false;
}
String packageName = newPackage.packageName;
- Log.i(TAG, "Enabling rollback for install of " + packageName
+ Slog.i(TAG, "Enabling rollback for install of " + packageName
+ ", session:" + session.sessionId);
String installerPackageName = session.getInstallerPackageName();
if (!enableRollbackAllowed(installerPackageName, packageName)) {
- Log.e(TAG, "Installer " + installerPackageName
+ Slog.e(TAG, "Installer " + installerPackageName
+ " is not allowed to enable rollback on " + packageName);
return false;
}
@@ -1016,7 +937,7 @@
} catch (PackageManager.NameNotFoundException e) {
// TODO: Support rolling back fresh package installs rather than
// fail here. Test this case.
- Log.e(TAG, packageName + " is not installed");
+ Slog.e(TAG, packageName + " is not installed");
return false;
}
@@ -1026,24 +947,23 @@
PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(
newVersion, installedVersion,
new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
- isApex, IntArray.wrap(installedUsers),
- new SparseLongArray() /* ceSnapshotInodes */);
+ isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */);
try {
ApplicationInfo appInfo = pkgInfo.applicationInfo;
- RollbackStore.backupPackageCodePath(data, packageName, appInfo.sourceDir);
+ RollbackStore.backupPackageCodePath(rollback, packageName, appInfo.sourceDir);
if (!ArrayUtils.isEmpty(appInfo.splitSourceDirs)) {
for (String sourceDir : appInfo.splitSourceDirs) {
- RollbackStore.backupPackageCodePath(data, packageName, sourceDir);
+ RollbackStore.backupPackageCodePath(rollback, packageName, sourceDir);
}
}
} catch (IOException e) {
- Log.e(TAG, "Unable to copy package for rollback for " + packageName, e);
+ Slog.e(TAG, "Unable to copy package for rollback for " + packageName, e);
return false;
}
synchronized (mLock) {
- data.info.getPackages().add(packageRollbackInfo);
+ rollback.info.getPackages().add(packageRollbackInfo);
}
return true;
}
@@ -1057,7 +977,7 @@
}
getHandler().post(() -> {
- snapshotUserDataInternal(packageName);
+ snapshotUserDataInternal(packageName, userIds);
restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token);
final PackageManagerInternal pmi = LocalServices.getService(
PackageManagerInternal.class);
@@ -1065,20 +985,20 @@
});
}
- private void snapshotUserDataInternal(String packageName) {
+ private void snapshotUserDataInternal(String packageName, int[] userIds) {
synchronized (mLock) {
// staged installs
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); i++) {
- RollbackData data = mRollbacks.get(i);
- if (data.state != RollbackData.ROLLBACK_STATE_ENABLING) {
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.state != Rollback.ROLLBACK_STATE_ENABLING) {
continue;
}
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)) {
- mAppDataRollbackHelper.snapshotAppData(data.info.getRollbackId(), info);
- saveRollbackData(data);
+ mAppDataRollbackHelper.snapshotAppData(
+ rollback.info.getRollbackId(), info, userIds);
+ saveRollback(rollback);
break;
}
}
@@ -1086,11 +1006,11 @@
// non-staged installs
PackageRollbackInfo info;
for (NewRollback rollback : mNewRollbacks) {
- info = getPackageRollbackInfo(rollback.data, packageName);
+ info = getPackageRollbackInfo(rollback.rollback, packageName);
if (info != null) {
- mAppDataRollbackHelper.snapshotAppData(rollback.data.info.getRollbackId(),
- info);
- saveRollbackData(rollback.data);
+ mAppDataRollbackHelper.snapshotAppData(
+ rollback.rollback.info.getRollbackId(), info, userIds);
+ saveRollback(rollback.rollback);
}
}
}
@@ -1099,32 +1019,31 @@
private void restoreUserDataInternal(String packageName, int[] userIds, int appId,
long ceDataInode, String seInfo, int token) {
PackageRollbackInfo info = null;
- RollbackData rollbackData = null;
+ Rollback rollback = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.restoreUserDataInProgress) {
- info = getPackageRollbackInfo(data, packageName);
+ Rollback candidate = mRollbacks.get(i);
+ if (candidate.restoreUserDataInProgress) {
+ info = getPackageRollbackInfo(candidate, packageName);
if (info != null) {
- rollbackData = data;
+ rollback = candidate;
break;
}
}
}
}
- if (rollbackData == null) {
+ if (rollback == null) {
return;
}
for (int userId : userIds) {
- final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
- rollbackData.info.getRollbackId(), info, userId, appId, seInfo);
+ final boolean changedRollback = mAppDataRollbackHelper.restoreAppData(
+ rollback.info.getRollbackId(), info, userId, appId, seInfo);
// We've updated metadata about this rollback, so save it to flash.
- if (changedRollbackData) {
- saveRollbackData(rollbackData);
+ if (changedRollback) {
+ saveRollback(rollback);
}
}
}
@@ -1143,7 +1062,7 @@
final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
if (session == null) {
- Log.e(TAG, "No matching install session for: " + sessionId);
+ Slog.e(TAG, "No matching install session for: " + sessionId);
result.offer(false);
return;
}
@@ -1154,9 +1073,8 @@
}
if (!session.isMultiPackage()) {
- if (!enableRollbackForPackageSession(newRollback.data, session,
- new int[0])) {
- Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
+ if (!enableRollbackForPackageSession(newRollback.rollback, session)) {
+ Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
}
@@ -1165,13 +1083,12 @@
final PackageInstaller.SessionInfo childSession =
installer.getSessionInfo(childSessionId);
if (childSession == null) {
- Log.e(TAG, "No matching child install session for: " + childSessionId);
+ Slog.e(TAG, "No matching child install session for: " + childSessionId);
result.offer(false);
return;
}
- if (!enableRollbackForPackageSession(newRollback.data, childSession,
- new int[0])) {
- Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
+ if (!enableRollbackForPackageSession(newRollback.rollback, childSession)) {
+ Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
}
@@ -1184,7 +1101,7 @@
try {
return result.take();
} catch (InterruptedException ie) {
- Log.e(TAG, "Interrupted while waiting for notifyStagedSession response");
+ Slog.e(TAG, "Interrupted while waiting for notifyStagedSession response");
return false;
}
}
@@ -1195,21 +1112,20 @@
throw new SecurityException("notifyStagedApkSession may only be called by the system.");
}
getHandler().post(() -> {
- RollbackData rd = null;
+ Rollback rollback = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.stagedSessionId == originalSessionId) {
- data.apkSessionId = apkSessionId;
- rd = data;
+ Rollback candidate = mRollbacks.get(i);
+ if (candidate.stagedSessionId == originalSessionId) {
+ candidate.apkSessionId = apkSessionId;
+ rollback = candidate;
break;
}
}
}
- if (rd != null) {
- saveRollbackData(rd);
+ if (rollback != null) {
+ saveRollback(rollback);
}
});
}
@@ -1289,7 +1205,8 @@
private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
- return a.getPackageName().equals(b.getPackageName())
+ return a != null && b != null
+ && a.getPackageName().equals(b.getPackageName())
&& a.getLongVersionCode() == b.getLongVersionCode();
}
@@ -1318,7 +1235,7 @@
}
if (newRollback != null) {
- RollbackData rollback = completeEnableRollback(newRollback, success);
+ Rollback rollback = completeEnableRollback(newRollback, success);
if (rollback != null && !rollback.isStaged()) {
makeRollbackAvailable(rollback);
}
@@ -1331,32 +1248,32 @@
* This should be called after rollback has been enabled for all packages
* in the rollback. It does not make the rollback available yet.
*
- * @return the rollback data for a successfully enable-completed rollback,
+ * @return the Rollback instance for a successfully enable-completed rollback,
* or null on error.
*/
- private RollbackData completeEnableRollback(NewRollback newRollback, boolean success) {
- RollbackData data = newRollback.data;
+ private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
+ Rollback rollback = newRollback.rollback;
if (!success) {
// The install session was aborted, clean up the pending install.
- deleteRollback(data);
+ deleteRollback(rollback);
return null;
}
if (newRollback.isCancelled) {
- Log.e(TAG, "Rollback has been cancelled by PackageManager");
- deleteRollback(data);
+ Slog.e(TAG, "Rollback has been cancelled by PackageManager");
+ deleteRollback(rollback);
return null;
}
- // It's safe to access data.info outside a synchronized block because
+ // It's safe to access rollback.info outside a synchronized block because
// this is running on the handler thread and all changes to the
- // data.info occur on the handler thread.
- if (data.info.getPackages().size() != newRollback.packageSessionIds.length) {
- Log.e(TAG, "Failed to enable rollback for all packages in session.");
- deleteRollback(data);
+ // rollback.info occur on the handler thread.
+ if (rollback.info.getPackages().size() != newRollback.packageSessionIds.length) {
+ Slog.e(TAG, "Failed to enable rollback for all packages in session.");
+ deleteRollback(rollback);
return null;
}
- saveRollbackData(data);
+ saveRollback(rollback);
synchronized (mLock) {
// Note: There is a small window of time between when
// the session has been committed by the package
@@ -1364,26 +1281,25 @@
// here. Presumably the window is small enough that
// nobody will want to roll back the newly installed
// package before we make the rollback available.
- // TODO: We'll lose the rollback data if the
+ // TODO: We'll lose the rollback if the
// device reboots between when the session is
// committed and this point. Revisit this after
// adding support for rollback of staged installs.
- ensureRollbackDataLoadedLocked();
- mRollbacks.add(data);
+ mRollbacks.add(rollback);
}
- return data;
+ return rollback;
}
- private void makeRollbackAvailable(RollbackData data) {
+ private void makeRollbackAvailable(Rollback rollback) {
// TODO: What if the rollback has since been expired, for example due
// to a new package being installed. Won't this revive an expired
// rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this.
synchronized (mLock) {
- data.state = RollbackData.ROLLBACK_STATE_AVAILABLE;
- data.timestamp = Instant.now();
+ rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE;
+ rollback.timestamp = Instant.now();
}
- saveRollbackData(data);
+ saveRollback(rollback);
// TODO(zezeozue): Provide API to explicitly start observing instead
// of doing this for all rollbacks. If we do this for all rollbacks,
@@ -1391,8 +1307,8 @@
// After enabling and commiting any rollback, observe packages and
// prepare to rollback if packages crashes too frequently.
List<String> packages = new ArrayList<>();
- for (int i = 0; i < data.info.getPackages().size(); i++) {
- packages.add(data.info.getPackages().get(i).getPackageName());
+ for (int i = 0; i < rollback.info.getPackages().size(); i++) {
+ packages.add(rollback.info.getPackages().get(i).getPackageName());
}
mPackageHealthObserver.startObservingHealth(packages,
mRollbackLifetimeDurationInMillis);
@@ -1400,18 +1316,14 @@
}
/*
- * Returns the RollbackData, if any, for a rollback with the given
- * rollbackId.
+ * Returns the rollback with the given rollbackId, if any.
*/
- private RollbackData getRollbackForId(int rollbackId) {
+ private Rollback getRollbackForId(int rollbackId) {
synchronized (mLock) {
- // TODO: Have ensureRollbackDataLoadedLocked return the list of
- // available rollbacks, to hopefully avoid forgetting to call it?
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
- RollbackData data = mRollbacks.get(i);
- if (data.info.getRollbackId() == rollbackId) {
- return data;
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.info.getRollbackId() == rollbackId) {
+ return rollback;
}
}
}
@@ -1421,11 +1333,11 @@
/**
* Returns the {@code PackageRollbackInfo} associated with {@code packageName} from
- * a specified {@code RollbackData}.
+ * a specified {@code Rollback}.
*/
- private static PackageRollbackInfo getPackageRollbackInfo(RollbackData data,
+ private static PackageRollbackInfo getPackageRollbackInfo(Rollback rollback,
String packageName) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
if (info.getPackageName().equals(packageName)) {
return info;
}
@@ -1449,30 +1361,30 @@
throw new IllegalStateException("Failed to allocate rollback ID");
}
- private void deleteRollback(RollbackData rollbackData) {
- for (PackageRollbackInfo info : rollbackData.info.getPackages()) {
- IntArray installedUsers = info.getInstalledUsers();
- for (int i = 0; i < installedUsers.size(); i++) {
- int userId = installedUsers.get(i);
- mAppDataRollbackHelper.destroyAppDataSnapshot(rollbackData.info.getRollbackId(),
+ private void deleteRollback(Rollback rollback) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
+ IntArray snapshottedUsers = info.getSnapshottedUsers();
+ for (int i = 0; i < snapshottedUsers.size(); i++) {
+ int userId = snapshottedUsers.get(i);
+ mAppDataRollbackHelper.destroyAppDataSnapshot(rollback.info.getRollbackId(),
info, userId);
}
}
- mRollbackStore.deleteRollbackData(rollbackData);
+ mRollbackStore.deleteRollback(rollback);
}
/**
- * Saves rollback data, swallowing any IOExceptions.
+ * Saves a rollback, swallowing any IOExceptions.
* For those times when it's not obvious what to do about the IOException.
* TODO: Double check we can't do a better job handling the IOException in
* a cases where this method is called.
*/
- private void saveRollbackData(RollbackData rollbackData) {
+ private void saveRollback(Rollback rollback) {
try {
- mRollbackStore.saveRollbackData(rollbackData);
+ mRollbackStore.saveRollback(rollback);
} catch (IOException ioe) {
- Log.e(TAG, "Unable to save rollback info for: "
- + rollbackData.info.getRollbackId(), ioe);
+ Slog.e(TAG, "Unable to save rollback for: "
+ + rollback.info.getRollbackId(), ioe);
}
}
@@ -1480,14 +1392,14 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
synchronized (mLock) {
- for (RollbackData data : mRollbacks) {
- RollbackInfo info = data.info;
+ for (Rollback rollback : mRollbacks) {
+ RollbackInfo info = rollback.info;
ipw.println(info.getRollbackId() + ":");
ipw.increaseIndent();
- ipw.println("-state: " + data.getStateAsString());
- ipw.println("-timestamp: " + data.timestamp);
- if (data.stagedSessionId != -1) {
- ipw.println("-stagedSessionId: " + data.stagedSessionId);
+ ipw.println("-state: " + rollback.getStateAsString());
+ ipw.println("-timestamp: " + rollback.timestamp);
+ if (rollback.stagedSessionId != -1) {
+ ipw.println("-stagedSessionId: " + rollback.stagedSessionId);
}
ipw.println("-packages:");
ipw.increaseIndent();
@@ -1497,7 +1409,7 @@
+ " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
}
ipw.decreaseIndent();
- if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) {
+ if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) {
ipw.println("-causePackages:");
ipw.increaseIndent();
for (VersionedPackage cPkg : info.getCausePackages()) {
@@ -1523,7 +1435,7 @@
}
private static class NewRollback {
- public final RollbackData data;
+ public final Rollback rollback;
/**
* This array holds all of the rollback tokens associated with package sessions included
@@ -1541,9 +1453,9 @@
public final int[] packageSessionIds;
/**
- * Flag to determine whether the RollbackData has been cancelled.
+ * Flag to determine whether the rollback has been cancelled.
*
- * <p>RollbackData could be invalidated and cancelled if RollbackManager receives
+ * <p>Rollback could be invalidated and cancelled if RollbackManager receives
* {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} from {@link PackageManager}.
*
* <p>The main underlying assumption here is that if enabling the rollback times out, then
@@ -1553,8 +1465,8 @@
*/
public boolean isCancelled = false;
- NewRollback(RollbackData data, int[] packageSessionIds) {
- this.data = data;
+ NewRollback(Rollback rollback, int[] packageSessionIds) {
+ this.rollback = rollback;
this.packageSessionIds = packageSessionIds;
}
@@ -1569,13 +1481,13 @@
NewRollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) {
int rollbackId = allocateRollbackIdLocked();
- final RollbackData data;
+ final Rollback rollback;
int parentSessionId = parentSession.getSessionId();
if (parentSession.isStaged()) {
- data = mRollbackStore.createStagedRollback(rollbackId, parentSessionId);
+ rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId);
} else {
- data = mRollbackStore.createNonStagedRollback(rollbackId);
+ rollback = mRollbackStore.createNonStagedRollback(rollbackId);
}
int[] packageSessionIds;
@@ -1585,7 +1497,7 @@
packageSessionIds = new int[]{parentSessionId};
}
- return new NewRollback(data, packageSessionIds);
+ return new NewRollback(rollback, packageSessionIds);
}
/**
@@ -1596,10 +1508,10 @@
NewRollback getNewRollbackForPackageSessionLocked(int packageSessionId) {
// We expect mNewRollbacks to be a very small list; linear search
// should be plenty fast.
- for (NewRollback newRollbackData : mNewRollbacks) {
- for (int id : newRollbackData.packageSessionIds) {
+ for (NewRollback newRollback: mNewRollbacks) {
+ for (int id : newRollback.packageSessionIds) {
if (id == packageSessionId) {
- return newRollbackData;
+ return newRollback;
}
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 8a26368c..b2448f6 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -16,8 +16,8 @@
package com.android.server.rollback;
-import static com.android.server.rollback.RollbackData.rollbackStateFromString;
-import static com.android.server.rollback.RollbackData.rollbackStateToString;
+import static com.android.server.rollback.Rollback.rollbackStateFromString;
+import static com.android.server.rollback.Rollback.rollbackStateToString;
import android.annotation.NonNull;
import android.content.pm.VersionedPackage;
@@ -25,7 +25,7 @@
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.content.rollback.RollbackInfo;
import android.util.IntArray;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseLongArray;
import libcore.io.IoUtils;
@@ -73,17 +73,17 @@
}
/**
- * Reads the rollback data from persistent storage.
+ * Reads the rollbacks from persistent storage.
*/
- List<RollbackData> loadAllRollbackData() {
- List<RollbackData> rollbacks = new ArrayList<>();
+ List<Rollback> loadRollbacks() {
+ List<Rollback> rollbacks = new ArrayList<>();
mRollbackDataDir.mkdirs();
for (File rollbackDir : mRollbackDataDir.listFiles()) {
if (rollbackDir.isDirectory()) {
try {
- rollbacks.add(loadRollbackData(rollbackDir));
+ rollbacks.add(loadRollback(rollbackDir));
} catch (IOException e) {
- Log.e(TAG, "Unable to read rollback data at " + rollbackDir, e);
+ Slog.e(TAG, "Unable to read rollback at " + rollbackDir, e);
removeFile(rollbackDir);
}
}
@@ -191,21 +191,21 @@
}
/**
- * Creates a new RollbackData instance for a non-staged rollback with
+ * Creates a new Rollback instance for a non-staged rollback with
* backupDir assigned.
*/
- RollbackData createNonStagedRollback(int rollbackId) {
+ Rollback createNonStagedRollback(int rollbackId) {
File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
- return new RollbackData(rollbackId, backupDir, -1);
+ return new Rollback(rollbackId, backupDir, -1);
}
/**
- * Creates a new RollbackData instance for a staged rollback with
+ * Creates a new Rollback instance for a staged rollback with
* backupDir assigned.
*/
- RollbackData createStagedRollback(int rollbackId, int stagedSessionId) {
+ Rollback createStagedRollback(int rollbackId, int stagedSessionId) {
File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
- return new RollbackData(rollbackId, backupDir, stagedSessionId);
+ return new Rollback(rollbackId, backupDir, stagedSessionId);
}
/**
@@ -213,10 +213,10 @@
* For packages containing splits, this method should be called for each
* of the package's split apks in addition to the base apk.
*/
- static void backupPackageCodePath(RollbackData data, String packageName, String codePath)
+ static void backupPackageCodePath(Rollback rollback, String packageName, String codePath)
throws IOException {
File sourceFile = new File(codePath);
- File targetDir = new File(data.backupDir, packageName);
+ File targetDir = new File(rollback.backupDir, packageName);
targetDir.mkdirs();
File targetFile = new File(targetDir, sourceFile.getName());
@@ -228,8 +228,8 @@
* Returns the apk or apex files backed up for the given package.
* Includes the base apk and any splits. Returns null if none found.
*/
- static File[] getPackageCodePaths(RollbackData data, String packageName) {
- File targetDir = new File(data.backupDir, packageName);
+ static File[] getPackageCodePaths(Rollback rollback, String packageName) {
+ File targetDir = new File(rollback.backupDir, packageName);
File[] files = targetDir.listFiles();
if (files == null || files.length == 0) {
return null;
@@ -241,27 +241,27 @@
* Deletes all backed up apks and apex files associated with the given
* rollback.
*/
- static void deletePackageCodePaths(RollbackData data) {
- for (PackageRollbackInfo info : data.info.getPackages()) {
- File targetDir = new File(data.backupDir, info.getPackageName());
+ static void deletePackageCodePaths(Rollback rollback) {
+ for (PackageRollbackInfo info : rollback.info.getPackages()) {
+ File targetDir = new File(rollback.backupDir, info.getPackageName());
removeFile(targetDir);
}
}
/**
- * Saves the rollback data to persistent storage.
+ * Saves the given rollback to persistent storage.
*/
- void saveRollbackData(RollbackData data) throws IOException {
+ void saveRollback(Rollback rollback) throws IOException {
try {
JSONObject dataJson = new JSONObject();
- dataJson.put("info", rollbackInfoToJson(data.info));
- dataJson.put("timestamp", data.timestamp.toString());
- dataJson.put("stagedSessionId", data.stagedSessionId);
- dataJson.put("state", rollbackStateToString(data.state));
- dataJson.put("apkSessionId", data.apkSessionId);
- dataJson.put("restoreUserDataInProgress", data.restoreUserDataInProgress);
+ dataJson.put("info", rollbackInfoToJson(rollback.info));
+ dataJson.put("timestamp", rollback.timestamp.toString());
+ dataJson.put("stagedSessionId", rollback.stagedSessionId);
+ dataJson.put("state", rollbackStateToString(rollback.state));
+ dataJson.put("apkSessionId", rollback.apkSessionId);
+ dataJson.put("restoreUserDataInProgress", rollback.restoreUserDataInProgress);
- PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
+ PrintWriter pw = new PrintWriter(new File(rollback.backupDir, "rollback.json"));
pw.println(dataJson.toString());
pw.close();
} catch (JSONException e) {
@@ -270,23 +270,23 @@
}
/**
- * Removes all persistant storage associated with the given rollback data.
+ * Removes all persistent storage associated with the given rollback.
*/
- void deleteRollbackData(RollbackData data) {
- removeFile(data.backupDir);
+ void deleteRollback(Rollback rollback) {
+ removeFile(rollback.backupDir);
}
/**
* Reads the metadata for a rollback from the given directory.
* @throws IOException in case of error reading the data.
*/
- private static RollbackData loadRollbackData(File backupDir) throws IOException {
+ private static Rollback loadRollback(File backupDir) throws IOException {
try {
File rollbackJsonFile = new File(backupDir, "rollback.json");
JSONObject dataJson = new JSONObject(
IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath()));
- return new RollbackData(
+ return new Rollback(
rollbackInfoFromJson(dataJson.getJSONObject("info")),
backupDir,
Instant.parse(dataJson.getString("timestamp")),
@@ -319,13 +319,14 @@
IntArray pendingBackups = info.getPendingBackups();
List<RestoreInfo> pendingRestores = info.getPendingRestores();
- IntArray installedUsers = info.getInstalledUsers();
+ IntArray snapshottedUsers = info.getSnapshottedUsers();
json.put("pendingBackups", convertToJsonArray(pendingBackups));
json.put("pendingRestores", convertToJsonArray(pendingRestores));
json.put("isApex", info.isApex());
- json.put("installedUsers", convertToJsonArray(installedUsers));
+ // Field is named 'installedUsers' for legacy reasons.
+ json.put("installedUsers", convertToJsonArray(snapshottedUsers));
json.put("ceSnapshotInodes", ceSnapshotInodesToJson(info.getCeSnapshotInodes()));
return json;
@@ -345,12 +346,13 @@
final boolean isApex = json.getBoolean("isApex");
- final IntArray installedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
+ // Field is named 'installedUsers' for legacy reasons.
+ final IntArray snapshottedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
final SparseLongArray ceSnapshotInodes = ceSnapshotInodesFromJson(
json.getJSONArray("ceSnapshotInodes"));
return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
- pendingBackups, pendingRestores, isApex, installedUsers, ceSnapshotInodes);
+ pendingBackups, pendingRestores, isApex, snapshottedUsers, ceSnapshotInodes);
}
private static JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING
index 8c7b5ac..2cc931b 100644
--- a/services/core/java/com/android/server/rollback/TEST_MAPPING
+++ b/services/core/java/com/android/server/rollback/TEST_MAPPING
@@ -1,12 +1,6 @@
{
"presubmit": [
{
- "name": "RollbackTest"
- },
- {
- "name": "StagedRollbackTest"
- },
- {
"name": "FrameworksServicesTests",
"options": [
{
@@ -21,6 +15,9 @@
},
{
"path": "cts/hostsidetests/rollback"
+ },
+ {
+ "path": "frameworks/base/tests/RollbackTest"
}
]
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 6175d41..7b3fbb9 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -130,7 +130,6 @@
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
"android.hardware.vibrator@1.3",
- "android.hardware.vibrator@1.4",
"android.hardware.vr@1.0",
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 3726228..746610d 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "VibratorService"
-#include <android/hardware/vibrator/1.4/IVibrator.h>
+#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/BnVibratorCallback.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <binder/IServiceManager.h>
@@ -43,166 +43,41 @@
namespace V1_1 = android::hardware::vibrator::V1_1;
namespace V1_2 = android::hardware::vibrator::V1_2;
namespace V1_3 = android::hardware::vibrator::V1_3;
-namespace V1_4 = android::hardware::vibrator::V1_4;
namespace aidl = android::hardware::vibrator;
namespace android {
static jmethodID sMethodIdOnComplete;
-// TODO(b/141828236): remove HIDL 1.4 and re-write all of this code to remove
-// shim
-class VibratorShim : public V1_4::IVibrator {
- public:
- VibratorShim(const sp<aidl::IVibrator>& vib) : mVib(vib) {}
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
+ static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
+ static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
+ static_cast<uint8_t>(aidl::EffectStrength::STRONG));
- Return<V1_0::Status> on(uint32_t timeoutMs) override {
- return on_1_4(timeoutMs, nullptr);
- }
+static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
+ static_cast<uint8_t>(aidl::Effect::CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
+ static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
+ static_cast<uint8_t>(aidl::Effect::TICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
+ static_cast<uint8_t>(aidl::Effect::THUD));
+static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
+ static_cast<uint8_t>(aidl::Effect::POP));
+static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
+ static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
+ static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
+ static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
+ static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
+ static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
- Return<V1_0::Status> off() override {
- return toHidlStatus(mVib->off());
- }
-
- Return<bool> supportsAmplitudeControl() override {
- int32_t cap = 0;
- if (!mVib->getCapabilities(&cap).isOk()) return false;
- if (mUnderExternalControl) {
- return (cap & aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
- } else {
- return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
- }
- }
-
- Return<V1_0::Status> setAmplitude(uint8_t amplitude) override {
- return toHidlStatus(mVib->setAmplitude(amplitude));
- }
-
- Return<void> perform(V1_0::Effect effect, V1_0::EffectStrength strength,
- perform_cb _hidl_cb) override {
- return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
- }
-
- Return<void> perform_1_1(V1_1::Effect_1_1 effect, V1_0::EffectStrength strength,
- perform_1_1_cb _hidl_cb) override {
- return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
- }
-
- Return<void> perform_1_2(V1_2::Effect effect, V1_0::EffectStrength strength,
- perform_1_2_cb _hidl_cb) override {
- return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
- }
-
- Return<bool> supportsExternalControl() override {
- int32_t cap = 0;
- if (!mVib->getCapabilities(&cap).isOk()) return false;
- return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
- }
-
- Return<V1_0::Status> setExternalControl(bool enabled) override {
- Return<V1_0::Status> status = toHidlStatus(mVib->setExternalControl(enabled));
- if (status.isOk() && status == V1_0::Status::OK) {
- mUnderExternalControl = enabled;
- }
- return status;
- }
-
- Return<void> perform_1_3(V1_3::Effect effect, V1_0::EffectStrength strength,
- perform_1_3_cb _hidl_cb) override {
- return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
- }
-
- Return<uint32_t> getCapabilities() override {
- static_assert(static_cast<int32_t>(V1_4::Capabilities::ON_COMPLETION_CALLBACK) ==
- static_cast<int32_t>(aidl::IVibrator::CAP_ON_CALLBACK));
- static_assert(static_cast<int32_t>(V1_4::Capabilities::PERFORM_COMPLETION_CALLBACK) ==
- static_cast<int32_t>(aidl::IVibrator::CAP_PERFORM_CALLBACK));
-
- int32_t cap;
- if (!mVib->getCapabilities(&cap).isOk()) return 0;
- return (cap & (aidl::IVibrator::CAP_ON_CALLBACK |
- aidl::IVibrator::CAP_PERFORM_CALLBACK)) > 0;
- }
-
- Return<V1_0::Status> on_1_4(uint32_t timeoutMs,
- const sp<V1_4::IVibratorCallback>& callback) override {
- sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
- return toHidlStatus(mVib->on(timeoutMs, cb));
- }
-
- Return<void> perform_1_4(V1_3::Effect effect, V1_0::EffectStrength strength,
- const sp<V1_4::IVibratorCallback>& callback,
- perform_1_4_cb _hidl_cb) override {
- static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
- static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
- static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
- static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
- static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
- static_cast<uint8_t>(aidl::EffectStrength::STRONG));
- static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
- static_cast<uint8_t>(aidl::Effect::CLICK));
- static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
- static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
- static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
- static_cast<uint8_t>(aidl::Effect::TICK));
- static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
- static_cast<uint8_t>(aidl::Effect::THUD));
- static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
- static_cast<uint8_t>(aidl::Effect::POP));
- static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
- static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
- static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
- static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
- static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
- static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
- static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
-
- sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
- int timeoutMs = 0;
- Return<V1_0::Status> status = toHidlStatus(
- mVib->perform(static_cast<aidl::Effect>(effect),
- static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs));
-
- if (status.isOk()) {
- _hidl_cb(status, timeoutMs);
- return android::hardware::Status::ok();
- } else {
- return android::hardware::details::StatusOf<V1_0::Status, void>(status);
- }
- }
- private:
- sp<aidl::IVibrator> mVib;
- bool mUnderExternalControl = false;
-
- Return<V1_0::Status> toHidlStatus(const android::binder::Status& status) {
- switch(status.exceptionCode()) {
- using android::hardware::Status;
- case Status::EX_NONE: return V1_0::Status::OK;
- case Status::EX_ILLEGAL_ARGUMENT: return V1_0::Status::BAD_VALUE;
- case Status::EX_UNSUPPORTED_OPERATION: return V1_0::Status::UNSUPPORTED_OPERATION;
- case Status::EX_TRANSACTION_FAILED: {
- return Status::fromStatusT(status.transactionError());
- }
- }
- return V1_0::Status::UNKNOWN_ERROR;
- }
-
- class CallbackShim : public aidl::BnVibratorCallback {
- public:
- CallbackShim(const sp<V1_4::IVibratorCallback>& cb) : mCb(cb) {}
- binder::Status onComplete() {
- mCb->onComplete();
- return binder::Status::ok(); // oneway, local call
- }
- private:
- sp<V1_4::IVibratorCallback> mCb;
- };
-};
-
-class VibratorCallback : public V1_4::IVibratorCallback {
+class VibratorCallback {
public:
VibratorCallback(JNIEnv *env, jobject vibration) :
mVibration(MakeGlobalRefOrDie(env, vibration)) {}
@@ -212,47 +87,92 @@
env->DeleteGlobalRef(mVibration);
}
- Return<void> onComplete() override {
+ void onComplete() {
auto env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(mVibration, sMethodIdOnComplete);
- return Void();
}
private:
jobject mVibration;
};
+class AidlVibratorCallback : public aidl::BnVibratorCallback {
+ public:
+ AidlVibratorCallback(JNIEnv *env, jobject vibration) :
+ mCb(env, vibration) {}
+
+ binder::Status onComplete() override {
+ mCb.onComplete();
+ return binder::Status::ok(); // oneway, local call
+ }
+
+ private:
+ VibratorCallback mCb;
+};
+
static constexpr int NUM_TRIES = 2;
+template<class R>
+inline R NoneStatus() {
+ using ::android::hardware::Status;
+ return Status::fromExceptionCode(Status::EX_NONE);
+}
+
+template<>
+inline binder::Status NoneStatus() {
+ using binder::Status;
+ return Status::fromExceptionCode(Status::EX_NONE);
+}
+
// Creates a Return<R> with STATUS::EX_NULL_POINTER.
template<class R>
-inline Return<R> NullptrStatus() {
+inline R NullptrStatus() {
using ::android::hardware::Status;
- return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)};
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+}
+
+template<>
+inline binder::Status NullptrStatus() {
+ using binder::Status;
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+}
+
+template <typename I>
+sp<I> getService() {
+ return I::getService();
+}
+
+template <>
+sp<aidl::IVibrator> getService() {
+ return waitForVintfService<aidl::IVibrator>();
+}
+
+template <typename I>
+sp<I> tryGetService() {
+ return I::tryGetService();
+}
+
+template <>
+sp<aidl::IVibrator> tryGetService() {
+ return checkVintfService<aidl::IVibrator>();
}
template <typename I>
class HalWrapper {
public:
static std::unique_ptr<HalWrapper> Create() {
- sp<aidl::IVibrator> aidlVib = waitForVintfService<aidl::IVibrator>();
- if (aidlVib) {
- return std::unique_ptr<HalWrapper>(new HalWrapper(new VibratorShim(aidlVib)));
- }
-
// Assume that if getService returns a nullptr, HAL is not available on the
// device.
- auto hal = I::getService();
+ auto hal = getService<I>();
return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
}
// Helper used to transparently deal with the vibrator HAL becoming unavailable.
template<class R, class... Args0, class... Args1>
- Return<R> call(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
+ R call(R (I::* fn)(Args0...), Args1&&... args1) {
// Return<R> doesn't have a default constructor, so make a Return<R> with
// STATUS::EX_NONE.
- using ::android::hardware::Status;
- Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)};
+ R ret{NoneStatus<R>()};
// Note that ret is guaranteed to be changed after this loop.
for (int i = 0; i < NUM_TRIES; ++i) {
@@ -266,12 +186,7 @@
ALOGE("Failed to issue command to vibrator HAL. Retrying.");
// Restoring connection to the HAL.
- sp<aidl::IVibrator> aidlVib = checkVintfService<aidl::IVibrator>();
- if (aidlVib) {
- mHal = new VibratorShim(aidlVib);
- } else {
- mHal = I::tryGetService();
- }
+ mHal = tryGetService<I>();
}
return ret;
}
@@ -290,7 +205,7 @@
}
template<class R, class I, class... Args0, class... Args1>
-Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
+R halCall(R (I::* fn)(Args0...), Args1&&... args1) {
auto hal = getHal<I>();
return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>();
}
@@ -307,110 +222,192 @@
static void vibratorInit(JNIEnv *env, jclass clazz)
{
- halCall(&V1_0::IVibrator::ping).isOk();
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ // IBinder::pingBinder isn't accessible as a pointer function
+ // but getCapabilities can serve the same purpose
+ int32_t cap;
+ hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
+ } else {
+ halCall(&V1_0::IVibrator::ping).isOk();
+ }
}
static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */)
{
- return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
+ bool ok;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ // IBinder::pingBinder isn't accessible as a pointer function
+ // but getCapabilities can serve the same purpose
+ int32_t cap;
+ ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
+ } else {
+ ok = halCall(&V1_0::IVibrator::ping).isOk();
+ }
+ return ok ? JNI_TRUE : JNI_FALSE;
}
static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
{
- Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
- if (retStatus != Status::OK) {
- ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr);
+ if (!status.isOk()) {
+ ALOGE("vibratorOn command failed: %s", status.toString8().string());
+ }
+ } else {
+ Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
+ if (retStatus != Status::OK) {
+ ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+ }
}
}
static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */)
{
- Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
- if (retStatus != Status::OK) {
- ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::off);
+ if (!status.isOk()) {
+ ALOGE("vibratorOff command failed: %s", status.toString8().string());
+ }
+ } else {
+ Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
+ if (retStatus != Status::OK) {
+ ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+ }
}
}
static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) {
- return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ int32_t cap = 0;
+ if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
+ return false;
+ }
+ return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
+ } else {
+ return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
+ }
}
static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) {
- Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
- .withDefault(Status::UNKNOWN_ERROR);
- if (status != Status::OK) {
- ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
- static_cast<uint32_t>(status));
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, amplitude);
+ if (!status.isOk()) {
+ ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string());
+ }
+ } else {
+ Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
+ .withDefault(Status::UNKNOWN_ERROR);
+ if (status != Status::OK) {
+ ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
+ static_cast<uint32_t>(status));
+ }
}
}
static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) {
- return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ int32_t cap = 0;
+ if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
+ return false;
+ }
+ return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
+ } else {
+ return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
+ }
}
static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) {
- Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
- .withDefault(Status::UNKNOWN_ERROR);
- if (status != Status::OK) {
- ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
- static_cast<uint32_t>(status));
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled);
+ if (!status.isOk()) {
+ ALOGE("Failed to set vibrator external control: %s", status.toString8().string());
+ }
+ } else {
+ Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
+ .withDefault(Status::UNKNOWN_ERROR);
+ if (status != Status::OK) {
+ ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
+ static_cast<uint32_t>(status));
+ }
}
}
static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
jobject vibration) {
- Status status;
- uint32_t lengthMs;
- auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
- status = retStatus;
- lengthMs = retLengthMs;
- };
- EffectStrength effectStrength(static_cast<EffectStrength>(strength));
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ int32_t lengthMs;
+ sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration);
+ aidl::Effect effectType(static_cast<aidl::Effect>(strength));
+ aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength));
- Return<void> ret;
- if (auto hal = getHal<V1_4::IVibrator>(); hal && isValidEffect<V1_3::Effect>(effect)) {
- sp<VibratorCallback> effectCallback = new VibratorCallback(env, vibration);
- ret = hal->call(&V1_4::IVibrator::perform_1_4, static_cast<V1_3::Effect>(effect),
- effectStrength, effectCallback, callback);
- } else if (isValidEffect<V1_0::Effect>(effect)) {
- ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
- effectStrength, callback);
- } else if (isValidEffect<Effect_1_1>(effect)) {
- ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
- effectStrength, callback);
- } else if (isValidEffect<V1_2::Effect>(effect)) {
- ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
- effectStrength, callback);
- } else if (isValidEffect<V1_3::Effect>(effect)) {
- ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
- effectStrength, callback);
- } else {
- ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
- static_cast<int32_t>(effect));
- return -1;
- }
-
- if (!ret.isOk()) {
- ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
- return -1;
- }
-
- if (status == Status::OK) {
+ auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs);
+ if (!status.isOk()) {
+ if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) {
+ ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
+ ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string());
+ }
+ return -1;
+ }
return lengthMs;
- } else if (status != Status::UNSUPPORTED_OPERATION) {
- // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
- // doesn't have a pre-defined waveform to perform for it, so we should just give the
- // opportunity to fall back to the framework waveforms.
- ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
- ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
- static_cast<int32_t>(strength), static_cast<uint32_t>(status));
+ } else {
+ Status status;
+ uint32_t lengthMs;
+ auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
+ status = retStatus;
+ lengthMs = retLengthMs;
+ };
+ EffectStrength effectStrength(static_cast<EffectStrength>(strength));
+
+ Return<void> ret;
+ if (isValidEffect<V1_0::Effect>(effect)) {
+ ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
+ effectStrength, callback);
+ } else if (isValidEffect<Effect_1_1>(effect)) {
+ ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
+ effectStrength, callback);
+ } else if (isValidEffect<V1_2::Effect>(effect)) {
+ ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
+ effectStrength, callback);
+ } else if (isValidEffect<V1_3::Effect>(effect)) {
+ ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
+ effectStrength, callback);
+ } else {
+ ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
+ static_cast<int32_t>(effect));
+ return -1;
+ }
+
+ if (!ret.isOk()) {
+ ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
+ return -1;
+ }
+
+ if (status == Status::OK) {
+ return lengthMs;
+ } else if (status != Status::UNSUPPORTED_OPERATION) {
+ // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
+ // doesn't have a pre-defined waveform to perform for it, so we should just give the
+ // opportunity to fall back to the framework waveforms.
+ ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
+ ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
+ static_cast<int32_t>(strength), static_cast<uint32_t>(status));
+ }
}
return -1;
}
static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
- return halCall(&V1_4::IVibrator::getCapabilities).withDefault(0);
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ int32_t cap = 0;
+ if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
+ return 0;
+ }
+ return cap;
+ }
+
+ return 0;
}
static const JNINativeMethod method_table[] = {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 16c60ca..313f884 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -135,6 +135,7 @@
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.power.ThermalManagerService;
+import com.android.server.recoverysystem.RecoverySystemService;
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
import com.android.server.rollback.RollbackManagerService;
@@ -698,7 +699,7 @@
// Bring up recovery system in case a rescue party needs a reboot
traceBeginAndSlog("StartRecoverySystemService");
- mSystemServiceManager.startService(RecoverySystemService.class);
+ mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
traceEnd();
// Now that we have the bare essentials of the OS up and running, take
diff --git a/services/net/Android.bp b/services/net/Android.bp
index c56ecd6..45430ea 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -1,38 +1,26 @@
java_library_static {
name: "services.net",
srcs: [
+ ":net-module-utils-srcs",
":tethering-servicesnet-srcs",
"java/**/*.java",
],
static_libs: [
"dnsresolver_aidl_interface-V2-java",
"netd_aidl_interface-unstable-java",
+ "netlink-client",
"networkstack-client",
"tethering-client",
],
}
filegroup {
- name: "services-networkstack-shared-srcs",
- srcs: [
- "java/android/net/ip/InterfaceController.java", // TODO: move to NetworkStack with tethering
- "java/android/net/util/InterfaceParams.java", // TODO: move to NetworkStack with IpServer
- "java/android/net/shared/*.java",
- "java/android/net/netlink/*.java",
- ],
-}
-
-filegroup {
name: "services-tethering-shared-srcs",
srcs: [
":framework-annotations",
"java/android/net/ConnectivityModuleConnector.java",
"java/android/net/NetworkStackClient.java",
- "java/android/net/ip/InterfaceController.java",
- "java/android/net/netlink/*.java",
- "java/android/net/util/InterfaceParams.java",
"java/android/net/util/NetdService.java",
"java/android/net/util/NetworkConstants.java",
- "java/android/net/util/SharedLog.java"
],
}
diff --git a/services/net/java/android/net/ip/InterfaceController.java b/services/net/java/android/net/ip/InterfaceController.java
deleted file mode 100644
index 970bc9c..0000000
--- a/services/net/java/android/net/ip/InterfaceController.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.net.ip;
-
-import android.net.INetd;
-import android.net.InterfaceConfigurationParcel;
-import android.net.LinkAddress;
-import android.net.util.SharedLog;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.system.OsConstants;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-
-
-/**
- * Encapsulates the multiple IP configuration operations performed on an interface.
- *
- * TODO: refactor/eliminate the redundant ways to set and clear addresses.
- *
- * @hide
- */
-public class InterfaceController {
- private final static boolean DBG = false;
-
- private final String mIfName;
- private final INetd mNetd;
- private final SharedLog mLog;
-
- public InterfaceController(String ifname, INetd netd, SharedLog log) {
- mIfName = ifname;
- mNetd = netd;
- mLog = log;
- }
-
- private boolean setInterfaceAddress(LinkAddress addr) {
- final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
- ifConfig.ifName = mIfName;
- ifConfig.ipv4Addr = addr.getAddress().getHostAddress();
- ifConfig.prefixLength = addr.getPrefixLength();
- ifConfig.hwAddr = "";
- ifConfig.flags = new String[0];
- try {
- mNetd.interfaceSetCfg(ifConfig);
- } catch (RemoteException | ServiceSpecificException e) {
- logError("Setting IPv4 address to %s/%d failed: %s",
- ifConfig.ipv4Addr, ifConfig.prefixLength, e);
- return false;
- }
- return true;
- }
-
- /**
- * Set the IPv4 address of the interface.
- */
- public boolean setIPv4Address(LinkAddress address) {
- if (!(address.getAddress() instanceof Inet4Address)) {
- return false;
- }
- return setInterfaceAddress(address);
- }
-
- /**
- * Clear the IPv4Address of the interface.
- */
- public boolean clearIPv4Address() {
- return setInterfaceAddress(new LinkAddress("0.0.0.0/0"));
- }
-
- private boolean setEnableIPv6(boolean enabled) {
- try {
- mNetd.interfaceSetEnableIPv6(mIfName, enabled);
- } catch (RemoteException | ServiceSpecificException e) {
- logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e);
- return false;
- }
- return true;
- }
-
- /**
- * Enable IPv6 on the interface.
- */
- public boolean enableIPv6() {
- return setEnableIPv6(true);
- }
-
- /**
- * Disable IPv6 on the interface.
- */
- public boolean disableIPv6() {
- return setEnableIPv6(false);
- }
-
- /**
- * Enable or disable IPv6 privacy extensions on the interface.
- * @param enabled Whether the extensions should be enabled.
- */
- public boolean setIPv6PrivacyExtensions(boolean enabled) {
- try {
- mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled);
- } catch (RemoteException | ServiceSpecificException e) {
- logError("error %s IPv6 privacy extensions: %s",
- (enabled ? "enabling" : "disabling"), e);
- return false;
- }
- return true;
- }
-
- /**
- * Set IPv6 address generation mode on the interface.
- *
- * <p>IPv6 should be disabled before changing the mode.
- */
- public boolean setIPv6AddrGenModeIfSupported(int mode) {
- try {
- mNetd.setIPv6AddrGenMode(mIfName, mode);
- } catch (RemoteException e) {
- logError("Unable to set IPv6 addrgen mode: %s", e);
- return false;
- } catch (ServiceSpecificException e) {
- if (e.errorCode != OsConstants.EOPNOTSUPP) {
- logError("Unable to set IPv6 addrgen mode: %s", e);
- return false;
- }
- }
- return true;
- }
-
- /**
- * Add an address to the interface.
- */
- public boolean addAddress(LinkAddress addr) {
- return addAddress(addr.getAddress(), addr.getPrefixLength());
- }
-
- /**
- * Add an address to the interface.
- */
- public boolean addAddress(InetAddress ip, int prefixLen) {
- try {
- mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen);
- } catch (ServiceSpecificException | RemoteException e) {
- logError("failed to add %s/%d: %s", ip, prefixLen, e);
- return false;
- }
- return true;
- }
-
- /**
- * Remove an address from the interface.
- */
- public boolean removeAddress(InetAddress ip, int prefixLen) {
- try {
- mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen);
- } catch (ServiceSpecificException | RemoteException e) {
- logError("failed to remove %s/%d: %s", ip, prefixLen, e);
- return false;
- }
- return true;
- }
-
- /**
- * Remove all addresses from the interface.
- */
- public boolean clearAllAddresses() {
- try {
- mNetd.interfaceClearAddrs(mIfName);
- } catch (Exception e) {
- logError("Failed to clear addresses: %s", e);
- return false;
- }
- return true;
- }
-
- private void logError(String fmt, Object... args) {
- mLog.e(String.format(fmt, args));
- }
-}
diff --git a/services/net/java/android/net/netlink/ConntrackMessage.java b/services/net/java/android/net/netlink/ConntrackMessage.java
deleted file mode 100644
index 6978739..0000000
--- a/services/net/java/android/net/netlink/ConntrackMessage.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-
-import android.system.OsConstants;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * A NetlinkMessage subclass for netlink conntrack messages.
- *
- * see also: <linux_src>/include/uapi/linux/netfilter/nfnetlink_conntrack.h
- *
- * @hide
- */
-public class ConntrackMessage extends NetlinkMessage {
- public static final int STRUCT_SIZE = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
-
- public static final short NFNL_SUBSYS_CTNETLINK = 1;
- public static final short IPCTNL_MSG_CT_NEW = 0;
-
- // enum ctattr_type
- public static final short CTA_TUPLE_ORIG = 1;
- public static final short CTA_TUPLE_REPLY = 2;
- public static final short CTA_TIMEOUT = 7;
-
- // enum ctattr_tuple
- public static final short CTA_TUPLE_IP = 1;
- public static final short CTA_TUPLE_PROTO = 2;
-
- // enum ctattr_ip
- public static final short CTA_IP_V4_SRC = 1;
- public static final short CTA_IP_V4_DST = 2;
-
- // enum ctattr_l4proto
- public static final short CTA_PROTO_NUM = 1;
- public static final short CTA_PROTO_SRC_PORT = 2;
- public static final short CTA_PROTO_DST_PORT = 3;
-
- public static byte[] newIPv4TimeoutUpdateRequest(
- int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) {
- // *** STYLE WARNING ***
- //
- // Code below this point uses extra block indentation to highlight the
- // packing of nested tuple netlink attribute types.
- final StructNlAttr ctaTupleOrig = new StructNlAttr(CTA_TUPLE_ORIG,
- new StructNlAttr(CTA_TUPLE_IP,
- new StructNlAttr(CTA_IP_V4_SRC, src),
- new StructNlAttr(CTA_IP_V4_DST, dst)),
- new StructNlAttr(CTA_TUPLE_PROTO,
- new StructNlAttr(CTA_PROTO_NUM, (byte) proto),
- new StructNlAttr(CTA_PROTO_SRC_PORT, (short) sport, BIG_ENDIAN),
- new StructNlAttr(CTA_PROTO_DST_PORT, (short) dport, BIG_ENDIAN)));
-
- final StructNlAttr ctaTimeout = new StructNlAttr(CTA_TIMEOUT, timeoutSec, BIG_ENDIAN);
-
- final int payloadLength = ctaTupleOrig.getAlignedLength() + ctaTimeout.getAlignedLength();
- final byte[] bytes = new byte[STRUCT_SIZE + payloadLength];
- final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.order(ByteOrder.nativeOrder());
-
- final ConntrackMessage ctmsg = new ConntrackMessage();
- ctmsg.mHeader.nlmsg_len = bytes.length;
- ctmsg.mHeader.nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW;
- ctmsg.mHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
- ctmsg.mHeader.nlmsg_seq = 1;
- ctmsg.pack(byteBuffer);
-
- ctaTupleOrig.pack(byteBuffer);
- ctaTimeout.pack(byteBuffer);
-
- return bytes;
- }
-
- protected StructNfGenMsg mNfGenMsg;
-
- private ConntrackMessage() {
- super(new StructNlMsgHdr());
- mNfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET);
- }
-
- public void pack(ByteBuffer byteBuffer) {
- mHeader.pack(byteBuffer);
- mNfGenMsg.pack(byteBuffer);
- }
-}
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
deleted file mode 100644
index ca07630..0000000
--- a/services/net/java/android/net/netlink/InetDiagMessage.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2018 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.net.netlink;
-
-import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
-import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.NETLINK_INET_DIAG;
-
-import android.annotation.Nullable;
-import android.net.util.SocketUtils;
-import android.system.ErrnoException;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * A NetlinkMessage subclass for netlink inet_diag messages.
- *
- * see also: <linux_src>/include/uapi/linux/inet_diag.h
- *
- * @hide
- */
-public class InetDiagMessage extends NetlinkMessage {
- public static final String TAG = "InetDiagMessage";
- private static final int TIMEOUT_MS = 500;
-
- public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
- InetSocketAddress remote, int family, short flags) {
- return InetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */,
- 0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES);
- }
-
- /**
- * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
- * if local and remote are not both null or both non-null.
- *
- * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
- * IPPROTO_UDP, or IPPROTO_UDPLITE.
- * @param local local socket address of the target socket. This will be packed into a
- * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
- * local or remote address is null.
- * @param remote remote socket address of the target socket. This will be packed into a
- * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
- * local or remote address is null.
- * @param family the ip family of the request message. This should be set to either AF_INET or
- * AF_INET6 for IPv4 or IPv6 sockets respectively.
- * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h.
- * @param pad for raw socket protocol specification.
- * @param idiagExt a set of flags defining what kind of extended information to report.
- * @param state a bit mask that defines a filter of socket states.
- *
- * @return bytes array representation of the message
- **/
- public static byte[] InetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
- @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt,
- int state) throws NullPointerException {
- final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
- final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.order(ByteOrder.nativeOrder());
-
- final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
- nlMsgHdr.nlmsg_len = bytes.length;
- nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
- nlMsgHdr.nlmsg_flags = flags;
- nlMsgHdr.pack(byteBuffer);
- final StructInetDiagReqV2 inetDiagReqV2 =
- new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state);
-
- inetDiagReqV2.pack(byteBuffer);
- return bytes;
- }
-
- public StructInetDiagMsg mStructInetDiagMsg;
-
- private InetDiagMessage(StructNlMsgHdr header) {
- super(header);
- mStructInetDiagMsg = new StructInetDiagMsg();
- }
-
- public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
- final InetDiagMessage msg = new InetDiagMessage(header);
- msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer);
- return msg;
- }
-
- private static int lookupUidByFamily(int protocol, InetSocketAddress local,
- InetSocketAddress remote, int family, short flags,
- FileDescriptor fd)
- throws ErrnoException, InterruptedIOException {
- byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags);
- NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
- ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);
-
- final NetlinkMessage nlMsg = NetlinkMessage.parse(response);
- final StructNlMsgHdr hdr = nlMsg.getHeader();
- if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
- return INVALID_UID;
- }
- if (nlMsg instanceof InetDiagMessage) {
- return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid;
- }
- return INVALID_UID;
- }
-
- private static final int FAMILY[] = {AF_INET6, AF_INET};
-
- private static int lookupUid(int protocol, InetSocketAddress local,
- InetSocketAddress remote, FileDescriptor fd)
- throws ErrnoException, InterruptedIOException {
- int uid;
-
- for (int family : FAMILY) {
- /**
- * For exact match lookup, swap local and remote for UDP lookups due to kernel
- * bug which will not be fixed. See aosp/755889 and
- * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
- */
- if (protocol == IPPROTO_UDP) {
- uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd);
- } else {
- uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd);
- }
- if (uid != INVALID_UID) {
- return uid;
- }
- }
-
- /**
- * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the
- * socket is not connected (and even if the socket is connected to a different destination).
- * If we want this API to work for such packets, then on miss we need to do a second lookup
- * with only the local address and port filled in.
- * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard.
- */
- if (protocol == IPPROTO_UDP) {
- try {
- InetSocketAddress wildcard = new InetSocketAddress(
- Inet6Address.getByName("::"), 0);
- uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6,
- (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
- if (uid != INVALID_UID) {
- return uid;
- }
- wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0);
- uid = lookupUidByFamily(protocol, local, wildcard, AF_INET,
- (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
- if (uid != INVALID_UID) {
- return uid;
- }
- } catch (UnknownHostException e) {
- Log.e(TAG, e.toString());
- }
- }
- return INVALID_UID;
- }
-
- /**
- * Use an inet_diag socket to look up the UID associated with the input local and remote
- * address/port and protocol of a connection.
- */
- public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
- InetSocketAddress remote) {
- int uid = INVALID_UID;
- FileDescriptor fd = null;
- try {
- fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
- NetlinkSocket.connectToKernel(fd);
- uid = lookupUid(protocol, local, remote, fd);
- } catch (ErrnoException | SocketException | IllegalArgumentException
- | InterruptedIOException e) {
- Log.e(TAG, e.toString());
- } finally {
- if (fd != null) {
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException e) {
- Log.e(TAG, e.toString());
- }
- }
- }
- return uid;
- }
-
- @Override
- public String toString() {
- return "InetDiagMessage{ "
- + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
- + "inet_diag_msg{"
- + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java
deleted file mode 100644
index fc1551c..0000000
--- a/services/net/java/android/net/netlink/NetlinkConstants.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.system.OsConstants;
-import com.android.internal.util.HexDump;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * Various constants and static helper methods for netlink communications.
- *
- * Values taken from:
- *
- * <linux_src>/include/uapi/linux/netlink.h
- * <linux_src>/include/uapi/linux/rtnetlink.h
- *
- * @hide
- */
-public class NetlinkConstants {
- private NetlinkConstants() {}
-
- public static final int NLA_ALIGNTO = 4;
-
- public static final int alignedLengthOf(short length) {
- final int intLength = (int) length & 0xffff;
- return alignedLengthOf(intLength);
- }
-
- public static final int alignedLengthOf(int length) {
- if (length <= 0) { return 0; }
- return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO);
- }
-
- public static String stringForAddressFamily(int family) {
- if (family == OsConstants.AF_INET) { return "AF_INET"; }
- if (family == OsConstants.AF_INET6) { return "AF_INET6"; }
- if (family == OsConstants.AF_NETLINK) { return "AF_NETLINK"; }
- return String.valueOf(family);
- }
-
- public static String stringForProtocol(int protocol) {
- if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
- if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
- return String.valueOf(protocol);
- }
-
- public static String hexify(byte[] bytes) {
- if (bytes == null) { return "(null)"; }
- return HexDump.toHexString(bytes);
- }
-
- public static String hexify(ByteBuffer buffer) {
- if (buffer == null) { return "(null)"; }
- return HexDump.toHexString(
- buffer.array(), buffer.position(), buffer.remaining());
- }
-
- // Known values for struct nlmsghdr nlm_type.
- public static final short NLMSG_NOOP = 1; // Nothing
- public static final short NLMSG_ERROR = 2; // Error
- public static final short NLMSG_DONE = 3; // End of a dump
- public static final short NLMSG_OVERRUN = 4; // Data lost
- public static final short NLMSG_MAX_RESERVED = 15; // Max reserved value
-
- public static final short RTM_NEWLINK = 16;
- public static final short RTM_DELLINK = 17;
- public static final short RTM_GETLINK = 18;
- public static final short RTM_SETLINK = 19;
- public static final short RTM_NEWADDR = 20;
- public static final short RTM_DELADDR = 21;
- public static final short RTM_GETADDR = 22;
- public static final short RTM_NEWROUTE = 24;
- public static final short RTM_DELROUTE = 25;
- public static final short RTM_GETROUTE = 26;
- public static final short RTM_NEWNEIGH = 28;
- public static final short RTM_DELNEIGH = 29;
- public static final short RTM_GETNEIGH = 30;
- public static final short RTM_NEWRULE = 32;
- public static final short RTM_DELRULE = 33;
- public static final short RTM_GETRULE = 34;
- public static final short RTM_NEWNDUSEROPT = 68;
-
- /* see <linux_src>/include/uapi/linux/sock_diag.h */
- public static final short SOCK_DIAG_BY_FAMILY = 20;
-
- public static String stringForNlMsgType(short nlm_type) {
- switch (nlm_type) {
- case NLMSG_NOOP: return "NLMSG_NOOP";
- case NLMSG_ERROR: return "NLMSG_ERROR";
- case NLMSG_DONE: return "NLMSG_DONE";
- case NLMSG_OVERRUN: return "NLMSG_OVERRUN";
- case RTM_NEWLINK: return "RTM_NEWLINK";
- case RTM_DELLINK: return "RTM_DELLINK";
- case RTM_GETLINK: return "RTM_GETLINK";
- case RTM_SETLINK: return "RTM_SETLINK";
- case RTM_NEWADDR: return "RTM_NEWADDR";
- case RTM_DELADDR: return "RTM_DELADDR";
- case RTM_GETADDR: return "RTM_GETADDR";
- case RTM_NEWROUTE: return "RTM_NEWROUTE";
- case RTM_DELROUTE: return "RTM_DELROUTE";
- case RTM_GETROUTE: return "RTM_GETROUTE";
- case RTM_NEWNEIGH: return "RTM_NEWNEIGH";
- case RTM_DELNEIGH: return "RTM_DELNEIGH";
- case RTM_GETNEIGH: return "RTM_GETNEIGH";
- case RTM_NEWRULE: return "RTM_NEWRULE";
- case RTM_DELRULE: return "RTM_DELRULE";
- case RTM_GETRULE: return "RTM_GETRULE";
- case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT";
- default:
- return "unknown RTM type: " + String.valueOf(nlm_type);
- }
- }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkErrorMessage.java b/services/net/java/android/net/netlink/NetlinkErrorMessage.java
deleted file mode 100644
index e275574..0000000
--- a/services/net/java/android/net/netlink/NetlinkErrorMessage.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.net.netlink.StructNlMsgHdr;
-import android.net.netlink.NetlinkMessage;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * A NetlinkMessage subclass for netlink error messages.
- *
- * @hide
- */
-public class NetlinkErrorMessage extends NetlinkMessage {
-
- public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
- final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header);
-
- errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer);
- if (errorMsg.mNlMsgErr == null) {
- return null;
- }
-
- return errorMsg;
- }
-
- private StructNlMsgErr mNlMsgErr;
-
- NetlinkErrorMessage(StructNlMsgHdr header) {
- super(header);
- mNlMsgErr = null;
- }
-
- public StructNlMsgErr getNlMsgError() {
- return mNlMsgErr;
- }
-
- @Override
- public String toString() {
- return "NetlinkErrorMessage{ "
- + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
- + "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java
deleted file mode 100644
index a325db8..0000000
--- a/services/net/java/android/net/netlink/NetlinkMessage.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNlAttr;
-import android.net.netlink.StructNlMsgHdr;
-import android.util.Log;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * NetlinkMessage base class for other, more specific netlink message types.
- *
- * Classes that extend NetlinkMessage should:
- * - implement a public static parse(StructNlMsgHdr, ByteBuffer) method
- * - returning either null (parse errors) or a new object of the subclass
- * type (cast-able to NetlinkMessage)
- *
- * NetlinkMessage.parse() should be updated to know which nlmsg_type values
- * correspond with which message subclasses.
- *
- * @hide
- */
-public class NetlinkMessage {
- private final static String TAG = "NetlinkMessage";
-
- public static NetlinkMessage parse(ByteBuffer byteBuffer) {
- final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1;
- final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer);
- if (nlmsghdr == null) {
- return null;
- }
-
- int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
- payloadLength -= StructNlMsgHdr.STRUCT_SIZE;
- if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) {
- // Malformed message or runt buffer. Pretend the buffer was consumed.
- byteBuffer.position(byteBuffer.limit());
- return null;
- }
-
- switch (nlmsghdr.nlmsg_type) {
- //case NetlinkConstants.NLMSG_NOOP:
- case NetlinkConstants.NLMSG_ERROR:
- return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
- case NetlinkConstants.NLMSG_DONE:
- byteBuffer.position(byteBuffer.position() + payloadLength);
- return new NetlinkMessage(nlmsghdr);
- //case NetlinkConstants.NLMSG_OVERRUN:
- case NetlinkConstants.RTM_NEWNEIGH:
- case NetlinkConstants.RTM_DELNEIGH:
- case NetlinkConstants.RTM_GETNEIGH:
- return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
- case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
- return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
- default:
- if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
- // Netlink control message. Just parse the header for now,
- // pretending the whole message was consumed.
- byteBuffer.position(byteBuffer.position() + payloadLength);
- return new NetlinkMessage(nlmsghdr);
- }
- return null;
- }
- }
-
- protected StructNlMsgHdr mHeader;
-
- public NetlinkMessage(StructNlMsgHdr nlmsghdr) {
- mHeader = nlmsghdr;
- }
-
- public StructNlMsgHdr getHeader() {
- return mHeader;
- }
-
- @Override
- public String toString() {
- return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
deleted file mode 100644
index 7311fc5..0000000
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
-import static android.system.OsConstants.AF_NETLINK;
-import static android.system.OsConstants.EIO;
-import static android.system.OsConstants.EPROTO;
-import static android.system.OsConstants.ETIMEDOUT;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_RCVBUF;
-import static android.system.OsConstants.SO_RCVTIMEO;
-import static android.system.OsConstants.SO_SNDTIMEO;
-
-import android.net.util.SocketUtils;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * NetlinkSocket
- *
- * A small static class to assist with AF_NETLINK socket operations.
- *
- * @hide
- */
-public class NetlinkSocket {
- private static final String TAG = "NetlinkSocket";
-
- public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
- public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
-
- public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
- final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
- final long IO_TIMEOUT = 300L;
-
- final FileDescriptor fd = forProto(nlProto);
-
- try {
- connectToKernel(fd);
- sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
- final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
- // recvMessage() guaranteed to not return null if it did not throw.
- final NetlinkMessage response = NetlinkMessage.parse(bytes);
- if (response != null && response instanceof NetlinkErrorMessage &&
- (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
- final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
- if (errno != 0) {
- // TODO: consider ignoring EINVAL (-22), which appears to be
- // normal when probing a neighbor for which the kernel does
- // not already have / no longer has a link layer address.
- Log.e(TAG, errPrefix + ", errmsg=" + response.toString());
- // Note: convert kernel errnos (negative) into userspace errnos (positive).
- throw new ErrnoException(response.toString(), Math.abs(errno));
- }
- } else {
- final String errmsg;
- if (response == null) {
- bytes.position(0);
- errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
- } else {
- errmsg = response.toString();
- }
- Log.e(TAG, errPrefix + ", errmsg=" + errmsg);
- throw new ErrnoException(errmsg, EPROTO);
- }
- } catch (InterruptedIOException e) {
- Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, ETIMEDOUT, e);
- } catch (SocketException e) {
- Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, EIO, e);
- } finally {
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException e) {
- // Nothing we can do here
- }
- }
- }
-
- public static FileDescriptor forProto(int nlProto) throws ErrnoException {
- final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto);
- Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE);
- return fd;
- }
-
- public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
- Os.connect(fd, makeNetlinkSocketAddress(0, 0));
- }
-
- private static void checkTimeout(long timeoutMs) {
- if (timeoutMs < 0) {
- throw new IllegalArgumentException("Negative timeouts not permitted");
- }
- }
-
- /**
- * Wait up to |timeoutMs| (or until underlying socket error) for a
- * netlink message of at most |bufsize| size.
- *
- * Multi-threaded calls with different timeouts will cause unexpected results.
- */
- public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
- throws ErrnoException, IllegalArgumentException, InterruptedIOException {
- checkTimeout(timeoutMs);
-
- Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
-
- ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
- int length = Os.read(fd, byteBuffer);
- if (length == bufsize) {
- Log.w(TAG, "maximum read");
- }
- byteBuffer.position(0);
- byteBuffer.limit(length);
- byteBuffer.order(ByteOrder.nativeOrder());
- return byteBuffer;
- }
-
- /**
- * Send a message to a peer to which this socket has previously connected,
- * waiting at most |timeoutMs| milliseconds for the send to complete.
- *
- * Multi-threaded calls with different timeouts will cause unexpected results.
- */
- public static int sendMessage(
- FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
- throws ErrnoException, IllegalArgumentException, InterruptedIOException {
- checkTimeout(timeoutMs);
- Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
- return Os.write(fd, bytes, offset, count);
- }
-}
diff --git a/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
deleted file mode 100644
index e784fbb..0000000
--- a/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-
-import android.net.netlink.StructNdaCacheInfo;
-import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNlAttr;
-import android.net.netlink.StructNlMsgHdr;
-import android.net.netlink.NetlinkMessage;
-import android.system.OsConstants;
-import android.util.Log;
-
-import java.net.InetAddress;
-import java.net.Inet6Address;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * A NetlinkMessage subclass for rtnetlink neighbor messages.
- *
- * see also: <linux_src>/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class RtNetlinkNeighborMessage extends NetlinkMessage {
- public static final short NDA_UNSPEC = 0;
- public static final short NDA_DST = 1;
- public static final short NDA_LLADDR = 2;
- public static final short NDA_CACHEINFO = 3;
- public static final short NDA_PROBES = 4;
- public static final short NDA_VLAN = 5;
- public static final short NDA_PORT = 6;
- public static final short NDA_VNI = 7;
- public static final short NDA_IFINDEX = 8;
- public static final short NDA_MASTER = 9;
-
- private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) {
- while (byteBuffer != null && byteBuffer.remaining() > 0) {
- final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
- if (nlAttr == null) {
- break;
- }
- if (nlAttr.nla_type == attrType) {
- return StructNlAttr.parse(byteBuffer);
- }
- if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
- break;
- }
- byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
- }
- return null;
- }
-
- public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
- final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header);
-
- neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer);
- if (neighMsg.mNdmsg == null) {
- return null;
- }
-
- // Some of these are message-type dependent, and not always present.
- final int baseOffset = byteBuffer.position();
- StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer);
- if (nlAttr != null) {
- neighMsg.mDestination = nlAttr.getValueAsInetAddress();
- }
-
- byteBuffer.position(baseOffset);
- nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer);
- if (nlAttr != null) {
- neighMsg.mLinkLayerAddr = nlAttr.nla_value;
- }
-
- byteBuffer.position(baseOffset);
- nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer);
- if (nlAttr != null) {
- neighMsg.mNumProbes = nlAttr.getValueAsInt(0);
- }
-
- byteBuffer.position(baseOffset);
- nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer);
- if (nlAttr != null) {
- neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer());
- }
-
- final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
- final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
- neighMsg.mHeader.nlmsg_len - kMinConsumed);
- if (byteBuffer.remaining() < kAdditionalSpace) {
- byteBuffer.position(byteBuffer.limit());
- } else {
- byteBuffer.position(baseOffset + kAdditionalSpace);
- }
-
- return neighMsg;
- }
-
- /**
- * A convenience method to create an RTM_GETNEIGH request message.
- */
- public static byte[] newGetNeighborsRequest(int seqNo) {
- final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
- final byte[] bytes = new byte[length];
- final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.order(ByteOrder.nativeOrder());
-
- final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
- nlmsghdr.nlmsg_len = length;
- nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
- nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- nlmsghdr.nlmsg_seq = seqNo;
- nlmsghdr.pack(byteBuffer);
-
- final StructNdMsg ndmsg = new StructNdMsg();
- ndmsg.pack(byteBuffer);
-
- return bytes;
- }
-
- /**
- * A convenience method to create an RTM_NEWNEIGH message, to modify
- * the kernel's state information for a specific neighbor.
- */
- public static byte[] newNewNeighborMessage(
- int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
- final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
- nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
- nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
- nlmsghdr.nlmsg_seq = seqNo;
-
- final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
- msg.mNdmsg = new StructNdMsg();
- msg.mNdmsg.ndm_family =
- (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
- msg.mNdmsg.ndm_ifindex = ifIndex;
- msg.mNdmsg.ndm_state = nudState;
- msg.mDestination = ip;
- msg.mLinkLayerAddr = llAddr; // might be null
-
- final byte[] bytes = new byte[msg.getRequiredSpace()];
- nlmsghdr.nlmsg_len = bytes.length;
- final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.order(ByteOrder.nativeOrder());
- msg.pack(byteBuffer);
- return bytes;
- }
-
- private StructNdMsg mNdmsg;
- private InetAddress mDestination;
- private byte[] mLinkLayerAddr;
- private int mNumProbes;
- private StructNdaCacheInfo mCacheInfo;
-
- private RtNetlinkNeighborMessage(StructNlMsgHdr header) {
- super(header);
- mNdmsg = null;
- mDestination = null;
- mLinkLayerAddr = null;
- mNumProbes = 0;
- mCacheInfo = null;
- }
-
- public StructNdMsg getNdHeader() {
- return mNdmsg;
- }
-
- public InetAddress getDestination() {
- return mDestination;
- }
-
- public byte[] getLinkLayerAddress() {
- return mLinkLayerAddr;
- }
-
- public int getProbes() {
- return mNumProbes;
- }
-
- public StructNdaCacheInfo getCacheInfo() {
- return mCacheInfo;
- }
-
- public int getRequiredSpace() {
- int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
- if (mDestination != null) {
- spaceRequired += NetlinkConstants.alignedLengthOf(
- StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
- }
- if (mLinkLayerAddr != null) {
- spaceRequired += NetlinkConstants.alignedLengthOf(
- StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
- }
- // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
- // attributes appended. Fix later, if necessary.
- return spaceRequired;
- }
-
- private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
- final StructNlAttr nlAttr = new StructNlAttr();
- nlAttr.nla_type = nlType;
- nlAttr.nla_value = nlValue;
- nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
- nlAttr.pack(byteBuffer);
- }
-
- public void pack(ByteBuffer byteBuffer) {
- getHeader().pack(byteBuffer) ;
- mNdmsg.pack(byteBuffer);
-
- if (mDestination != null) {
- packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
- }
- if (mLinkLayerAddr != null) {
- packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
- }
- }
-
- @Override
- public String toString() {
- final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
- return "RtNetlinkNeighborMessage{ "
- + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
- + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, "
- + "destination{" + ipLiteral + "} "
- + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} "
- + "probes{" + mNumProbes + "} "
- + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructInetDiagMsg.java b/services/net/java/android/net/netlink/StructInetDiagMsg.java
deleted file mode 100644
index da824ad..0000000
--- a/services/net/java/android/net/netlink/StructInetDiagMsg.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 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.net.netlink;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import android.util.Log;
-
-/**
- * struct inet_diag_msg
- *
- * see <linux_src>/include/uapi/linux/inet_diag.h
- *
- * struct inet_diag_msg {
- * __u8 idiag_family;
- * __u8 idiag_state;
- * __u8 idiag_timer;
- * __u8 idiag_retrans;
- * struct inet_diag_sockid id;
- * __u32 idiag_expires;
- * __u32 idiag_rqueue;
- * __u32 idiag_wqueue;
- * __u32 idiag_uid;
- * __u32 idiag_inode;
- * };
- *
- * @hide
- */
-public class StructInetDiagMsg {
- public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20;
- private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 +
- StructInetDiagSockId.STRUCT_SIZE + 12;
- public int idiag_uid;
-
- public static StructInetDiagMsg parse(ByteBuffer byteBuffer) {
- StructInetDiagMsg struct = new StructInetDiagMsg();
- struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET);
- return struct;
- }
-
- @Override
- public String toString() {
- return "StructInetDiagMsg{ "
- + "idiag_uid{" + idiag_uid + "}, "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
deleted file mode 100644
index 2268113..0000000
--- a/services/net/java/android/net/netlink/StructInetDiagReqV2.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2018 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.net.netlink;
-
-import android.annotation.Nullable;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-
-/**
- * struct inet_diag_req_v2
- *
- * see <linux_src>/include/uapi/linux/inet_diag.h
- *
- * struct inet_diag_req_v2 {
- * __u8 sdiag_family;
- * __u8 sdiag_protocol;
- * __u8 idiag_ext;
- * __u8 pad;
- * __u32 idiag_states;
- * struct inet_diag_sockid id;
- * };
- *
- * @hide
- */
-public class StructInetDiagReqV2 {
- public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
-
- private final byte mSdiagFamily;
- private final byte mSdiagProtocol;
- private final byte mIdiagExt;
- private final byte mPad;
- private final StructInetDiagSockId mId;
- private final int mState;
- public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
-
- public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
- int family) {
- this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */,
- INET_DIAG_REQ_V2_ALL_STATES);
- }
-
- public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
- @Nullable InetSocketAddress remote, int family, int pad, int extension, int state)
- throws NullPointerException {
- mSdiagFamily = (byte) family;
- mSdiagProtocol = (byte) protocol;
- // Request for all sockets if no specific socket is requested. Specify the local and remote
- // socket address information for target request socket.
- if ((local == null) != (remote == null)) {
- throw new NullPointerException("Local and remote must be both null or both non-null");
- }
- mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null);
- mPad = (byte) pad;
- mIdiagExt = (byte) extension;
- mState = state;
- }
-
- public void pack(ByteBuffer byteBuffer) {
- // The ByteOrder must have already been set by the caller.
- byteBuffer.put((byte) mSdiagFamily);
- byteBuffer.put((byte) mSdiagProtocol);
- byteBuffer.put((byte) mIdiagExt);
- byteBuffer.put((byte) mPad);
- byteBuffer.putInt(mState);
- if (mId != null) mId.pack(byteBuffer);
- }
-
- @Override
- public String toString() {
- final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily);
- final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol);
-
- return "StructInetDiagReqV2{ "
- + "sdiag_family{" + familyStr + "}, "
- + "sdiag_protocol{" + protocolStr + "}, "
- + "idiag_ext{" + mIdiagExt + ")}, "
- + "pad{" + mPad + "}, "
- + "idiag_states{" + Integer.toHexString(mState) + "}, "
- + ((mId != null) ? mId.toString() : "inet_diag_sockid=null")
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructInetDiagSockId.java b/services/net/java/android/net/netlink/StructInetDiagSockId.java
deleted file mode 100644
index 2e9fa25..0000000
--- a/services/net/java/android/net/netlink/StructInetDiagSockId.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2018 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.net.netlink;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * struct inet_diag_req_v2
- *
- * see <linux_src>/include/uapi/linux/inet_diag.h
- *
- * struct inet_diag_sockid {
- * __be16 idiag_sport;
- * __be16 idiag_dport;
- * __be32 idiag_src[4];
- * __be32 idiag_dst[4];
- * __u32 idiag_if;
- * __u32 idiag_cookie[2];
- * #define INET_DIAG_NOCOOKIE (~0U)
- * };
- *
- * @hide
- */
-public class StructInetDiagSockId {
- public static final int STRUCT_SIZE = 48;
-
- private final InetSocketAddress mLocSocketAddress;
- private final InetSocketAddress mRemSocketAddress;
- private final byte[] INET_DIAG_NOCOOKIE = new byte[]{
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
- private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) {
- mLocSocketAddress = loc;
- mRemSocketAddress = rem;
- }
-
- public void pack(ByteBuffer byteBuffer) {
- byteBuffer.order(BIG_ENDIAN);
- byteBuffer.putShort((short) mLocSocketAddress.getPort());
- byteBuffer.putShort((short) mRemSocketAddress.getPort());
- byteBuffer.put(mLocSocketAddress.getAddress().getAddress());
- if (mLocSocketAddress.getAddress() instanceof Inet4Address) {
- byteBuffer.put(IPV4_PADDING);
- }
- byteBuffer.put(mRemSocketAddress.getAddress().getAddress());
- if (mRemSocketAddress.getAddress() instanceof Inet4Address) {
- byteBuffer.put(IPV4_PADDING);
- }
- byteBuffer.order(ByteOrder.nativeOrder());
- byteBuffer.putInt(0);
- byteBuffer.put(INET_DIAG_NOCOOKIE);
- }
-
- @Override
- public String toString() {
- return "StructInetDiagSockId{ "
- + "idiag_sport{" + mLocSocketAddress.getPort() + "}, "
- + "idiag_dport{" + mRemSocketAddress.getPort() + "}, "
- + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, "
- + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, "
- + "idiag_if{" + 0 + "} "
- + "idiag_cookie{INET_DIAG_NOCOOKIE}"
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java
deleted file mode 100644
index e34ec39..0000000
--- a/services/net/java/android/net/netlink/StructNdMsg.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import android.system.OsConstants;
-import java.nio.ByteBuffer;
-
-
-/**
- * struct ndmsg
- *
- * see: <linux_src>/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class StructNdMsg {
- // Already aligned.
- public static final int STRUCT_SIZE = 12;
-
- // Neighbor Cache Entry States
- public static final short NUD_NONE = 0x00;
- public static final short NUD_INCOMPLETE = 0x01;
- public static final short NUD_REACHABLE = 0x02;
- public static final short NUD_STALE = 0x04;
- public static final short NUD_DELAY = 0x08;
- public static final short NUD_PROBE = 0x10;
- public static final short NUD_FAILED = 0x20;
- public static final short NUD_NOARP = 0x40;
- public static final short NUD_PERMANENT = 0x80;
-
- public static String stringForNudState(short nudState) {
- switch (nudState) {
- case NUD_NONE: return "NUD_NONE";
- case NUD_INCOMPLETE: return "NUD_INCOMPLETE";
- case NUD_REACHABLE: return "NUD_REACHABLE";
- case NUD_STALE: return "NUD_STALE";
- case NUD_DELAY: return "NUD_DELAY";
- case NUD_PROBE: return "NUD_PROBE";
- case NUD_FAILED: return "NUD_FAILED";
- case NUD_NOARP: return "NUD_NOARP";
- case NUD_PERMANENT: return "NUD_PERMANENT";
- default:
- return "unknown NUD state: " + String.valueOf(nudState);
- }
- }
-
- public static boolean isNudStateConnected(short nudState) {
- return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
- }
-
- public static boolean isNudStateValid(short nudState) {
- return (isNudStateConnected(nudState) ||
- ((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
- }
-
- // Neighbor Cache Entry Flags
- public static byte NTF_USE = (byte) 0x01;
- public static byte NTF_SELF = (byte) 0x02;
- public static byte NTF_MASTER = (byte) 0x04;
- public static byte NTF_PROXY = (byte) 0x08;
- public static byte NTF_ROUTER = (byte) 0x80;
-
- public static String stringForNudFlags(byte flags) {
- final StringBuilder sb = new StringBuilder();
- if ((flags & NTF_USE) != 0) {
- sb.append("NTF_USE");
- }
- if ((flags & NTF_SELF) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NTF_SELF");
- }
- if ((flags & NTF_MASTER) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NTF_MASTER");
- }
- if ((flags & NTF_PROXY) != 0) {
- if (sb.length() > 0) { sb.append("|");
- }
- sb.append("NTF_PROXY"); }
- if ((flags & NTF_ROUTER) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NTF_ROUTER");
- }
- return sb.toString();
- }
-
- private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
- return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
- }
-
- public static StructNdMsg parse(ByteBuffer byteBuffer) {
- if (!hasAvailableSpace(byteBuffer)) { return null; }
-
- // The ByteOrder must have already been set by the caller. In most
- // cases ByteOrder.nativeOrder() is correct, with the possible
- // exception of usage within unittests.
- final StructNdMsg struct = new StructNdMsg();
- struct.ndm_family = byteBuffer.get();
- final byte pad1 = byteBuffer.get();
- final short pad2 = byteBuffer.getShort();
- struct.ndm_ifindex = byteBuffer.getInt();
- struct.ndm_state = byteBuffer.getShort();
- struct.ndm_flags = byteBuffer.get();
- struct.ndm_type = byteBuffer.get();
- return struct;
- }
-
- public byte ndm_family;
- public int ndm_ifindex;
- public short ndm_state;
- public byte ndm_flags;
- public byte ndm_type;
-
- public StructNdMsg() {
- ndm_family = (byte) OsConstants.AF_UNSPEC;
- }
-
- public void pack(ByteBuffer byteBuffer) {
- // The ByteOrder must have already been set by the caller. In most
- // cases ByteOrder.nativeOrder() is correct, with the exception
- // of usage within unittests.
- byteBuffer.put(ndm_family);
- byteBuffer.put((byte) 0); // pad1
- byteBuffer.putShort((short) 0); // pad2
- byteBuffer.putInt(ndm_ifindex);
- byteBuffer.putShort(ndm_state);
- byteBuffer.put(ndm_flags);
- byteBuffer.put(ndm_type);
- }
-
- public boolean nudConnected() {
- return isNudStateConnected(ndm_state);
- }
-
- public boolean nudValid() {
- return isNudStateValid(ndm_state);
- }
-
- @Override
- public String toString() {
- final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")";
- final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")";
- return "StructNdMsg{ "
- + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, "
- + "ifindex{" + ndm_ifindex + "}, "
- + "state{" + stateStr + "}, "
- + "flags{" + flagsStr + "}, "
- + "type{" + ndm_type + "} "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructNdaCacheInfo.java b/services/net/java/android/net/netlink/StructNdaCacheInfo.java
deleted file mode 100644
index 16cf563..0000000
--- a/services/net/java/android/net/netlink/StructNdaCacheInfo.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.system.Os;
-import android.system.OsConstants;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nda_cacheinfo
- *
- * see: <linux_src>/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class StructNdaCacheInfo {
- // Already aligned.
- public static final int STRUCT_SIZE = 16;
-
- private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
- return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
- }
-
- public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) {
- if (!hasAvailableSpace(byteBuffer)) { return null; }
-
- // The ByteOrder must have already been set by the caller. In most
- // cases ByteOrder.nativeOrder() is correct, with the possible
- // exception of usage within unittests.
- final StructNdaCacheInfo struct = new StructNdaCacheInfo();
- struct.ndm_used = byteBuffer.getInt();
- struct.ndm_confirmed = byteBuffer.getInt();
- struct.ndm_updated = byteBuffer.getInt();
- struct.ndm_refcnt = byteBuffer.getInt();
- return struct;
- }
-
- // TODO: investigate whether this can change during device runtime and
- // decide what (if anything) should be done about that.
- private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK);
-
- private static long ticksToMilliSeconds(int intClockTicks) {
- final long longClockTicks = (long) intClockTicks & 0xffffffff;
- return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND;
- }
-
- /**
- * Explanatory notes, for reference.
- *
- * Before being returned to user space, the neighbor entry times are
- * converted to clock_t's like so:
- *
- * ndm_used = jiffies_to_clock_t(now - neigh->used);
- * ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
- * ndm_updated = jiffies_to_clock_t(now - neigh->updated);
- *
- * meaning that these values are expressed as "clock ticks ago". To
- * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK).
- * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed
- * in centiseconds.
- *
- * These values are unsigned, but fortunately being expressed as "some
- * clock ticks ago", these values are typically very small (and
- * 2^31 centiseconds = 248 days).
- *
- * By observation, it appears that:
- * ndm_used: the last time ARP/ND took place for this neighbor
- * ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR
- * higher layer confirmation (TCP or MSG_CONFIRM)
- * was received
- * ndm_updated: the time when the current NUD state was entered
- */
- public int ndm_used;
- public int ndm_confirmed;
- public int ndm_updated;
- public int ndm_refcnt;
-
- public StructNdaCacheInfo() {}
-
- public long lastUsed() {
- return ticksToMilliSeconds(ndm_used);
- }
-
- public long lastConfirmed() {
- return ticksToMilliSeconds(ndm_confirmed);
- }
-
- public long lastUpdated() {
- return ticksToMilliSeconds(ndm_updated);
- }
-
- @Override
- public String toString() {
- return "NdaCacheInfo{ "
- + "ndm_used{" + lastUsed() + "}, "
- + "ndm_confirmed{" + lastConfirmed() + "}, "
- + "ndm_updated{" + lastUpdated() + "}, "
- + "ndm_refcnt{" + ndm_refcnt + "} "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructNfGenMsg.java b/services/net/java/android/net/netlink/StructNfGenMsg.java
deleted file mode 100644
index 8155977..0000000
--- a/services/net/java/android/net/netlink/StructNfGenMsg.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.net.netlink;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nfgenmsg
- *
- * see <linux_src>/include/uapi/linux/netfilter/nfnetlink.h
- *
- * @hide
- */
-public class StructNfGenMsg {
- public static final int STRUCT_SIZE = 2 + Short.BYTES;
-
- public static final int NFNETLINK_V0 = 0;
-
- final public byte nfgen_family;
- final public byte version;
- final public short res_id; // N.B.: this is big endian in the kernel
-
- public StructNfGenMsg(byte family) {
- nfgen_family = family;
- version = (byte) NFNETLINK_V0;
- res_id = (short) 0;
- }
-
- public void pack(ByteBuffer byteBuffer) {
- byteBuffer.put(nfgen_family);
- byteBuffer.put(version);
- byteBuffer.putShort(res_id);
- }
-}
diff --git a/services/net/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java
deleted file mode 100644
index 28a4e88..0000000
--- a/services/net/java/android/net/netlink/StructNlAttr.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlattr
- *
- * see: <linux_src>/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlAttr {
- // Already aligned.
- public static final int NLA_HEADERLEN = 4;
- public static final int NLA_F_NESTED = (1 << 15);
-
- public static short makeNestedType(short type) {
- return (short) (type | NLA_F_NESTED);
- }
-
- // Return a (length, type) object only, without consuming any bytes in
- // |byteBuffer| and without copying or interpreting any value bytes.
- // This is used for scanning over a packed set of struct nlattr's,
- // looking for instances of a particular type.
- public static StructNlAttr peek(ByteBuffer byteBuffer) {
- if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) {
- return null;
- }
- final int baseOffset = byteBuffer.position();
-
- // Assume the byte order of the buffer is the expected byte order of the value.
- final StructNlAttr struct = new StructNlAttr(byteBuffer.order());
- // The byte order of nla_len and nla_type is always native.
- final ByteOrder originalOrder = byteBuffer.order();
- byteBuffer.order(ByteOrder.nativeOrder());
- try {
- struct.nla_len = byteBuffer.getShort();
- struct.nla_type = byteBuffer.getShort();
- } finally {
- byteBuffer.order(originalOrder);
- }
-
- byteBuffer.position(baseOffset);
- if (struct.nla_len < NLA_HEADERLEN) {
- // Malformed.
- return null;
- }
- return struct;
- }
-
- public static StructNlAttr parse(ByteBuffer byteBuffer) {
- final StructNlAttr struct = peek(byteBuffer);
- if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) {
- return null;
- }
-
- final int baseOffset = byteBuffer.position();
- byteBuffer.position(baseOffset + NLA_HEADERLEN);
-
- int valueLen = ((int) struct.nla_len) & 0xffff;
- valueLen -= NLA_HEADERLEN;
- if (valueLen > 0) {
- struct.nla_value = new byte[valueLen];
- byteBuffer.get(struct.nla_value, 0, valueLen);
- byteBuffer.position(baseOffset + struct.getAlignedLength());
- }
- return struct;
- }
-
- public short nla_len = (short) NLA_HEADERLEN;
- public short nla_type;
- public byte[] nla_value;
-
- // The byte order used to read/write the value member. Netlink length and
- // type members are always read/written in native order.
- private ByteOrder mByteOrder = ByteOrder.nativeOrder();
-
- public StructNlAttr() {}
-
- public StructNlAttr(ByteOrder byteOrder) {
- mByteOrder = byteOrder;
- }
-
- public StructNlAttr(short type, byte value) {
- nla_type = type;
- setValue(new byte[1]);
- nla_value[0] = value;
- }
-
- public StructNlAttr(short type, short value) {
- this(type, value, ByteOrder.nativeOrder());
- }
-
- public StructNlAttr(short type, short value, ByteOrder order) {
- this(order);
- nla_type = type;
- setValue(new byte[Short.BYTES]);
- getValueAsByteBuffer().putShort(value);
- }
-
- public StructNlAttr(short type, int value) {
- this(type, value, ByteOrder.nativeOrder());
- }
-
- public StructNlAttr(short type, int value, ByteOrder order) {
- this(order);
- nla_type = type;
- setValue(new byte[Integer.BYTES]);
- getValueAsByteBuffer().putInt(value);
- }
-
- public StructNlAttr(short type, InetAddress ip) {
- nla_type = type;
- setValue(ip.getAddress());
- }
-
- public StructNlAttr(short type, StructNlAttr... nested) {
- this();
- nla_type = makeNestedType(type);
-
- int payloadLength = 0;
- for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength();
- setValue(new byte[payloadLength]);
-
- final ByteBuffer buf = getValueAsByteBuffer();
- for (StructNlAttr nla : nested) {
- nla.pack(buf);
- }
- }
-
- public int getAlignedLength() {
- return NetlinkConstants.alignedLengthOf(nla_len);
- }
-
- public ByteBuffer getValueAsByteBuffer() {
- if (nla_value == null) { return null; }
- final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
- byteBuffer.order(mByteOrder);
- return byteBuffer;
- }
-
- public int getValueAsInt(int defaultValue) {
- final ByteBuffer byteBuffer = getValueAsByteBuffer();
- if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
- return defaultValue;
- }
- return getValueAsByteBuffer().getInt();
- }
-
- public InetAddress getValueAsInetAddress() {
- if (nla_value == null) { return null; }
-
- try {
- return InetAddress.getByAddress(nla_value);
- } catch (UnknownHostException ignored) {
- return null;
- }
- }
-
- public void pack(ByteBuffer byteBuffer) {
- final ByteOrder originalOrder = byteBuffer.order();
- final int originalPosition = byteBuffer.position();
-
- byteBuffer.order(ByteOrder.nativeOrder());
- try {
- byteBuffer.putShort(nla_len);
- byteBuffer.putShort(nla_type);
- if (nla_value != null) byteBuffer.put(nla_value);
- } finally {
- byteBuffer.order(originalOrder);
- }
- byteBuffer.position(originalPosition + getAlignedLength());
- }
-
- private void setValue(byte[] value) {
- nla_value = value;
- nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0));
- }
-
- @Override
- public String toString() {
- return "StructNlAttr{ "
- + "nla_len{" + nla_len + "}, "
- + "nla_type{" + nla_type + "}, "
- + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java
deleted file mode 100644
index 6fcc6e6..0000000
--- a/services/net/java/android/net/netlink/StructNlMsgErr.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.StructNlMsgHdr;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlmsgerr
- *
- * see <linux_src>/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlMsgErr {
- public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE;
-
- public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
- return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
- }
-
- public static StructNlMsgErr parse(ByteBuffer byteBuffer) {
- if (!hasAvailableSpace(byteBuffer)) { return null; }
-
- // The ByteOrder must have already been set by the caller. In most
- // cases ByteOrder.nativeOrder() is correct, with the exception
- // of usage within unittests.
- final StructNlMsgErr struct = new StructNlMsgErr();
- struct.error = byteBuffer.getInt();
- struct.msg = StructNlMsgHdr.parse(byteBuffer);
- return struct;
- }
-
- public int error;
- public StructNlMsgHdr msg;
-
- public void pack(ByteBuffer byteBuffer) {
- // The ByteOrder must have already been set by the caller. In most
- // cases ByteOrder.nativeOrder() is correct, with the possible
- // exception of usage within unittests.
- byteBuffer.putInt(error);
- if (msg != null) {
- msg.pack(byteBuffer);
- }
- }
-
- @Override
- public String toString() {
- return "StructNlMsgErr{ "
- + "error{" + error + "}, "
- + "msg{" + (msg == null ? "" : msg.toString()) + "} "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/netlink/StructNlMsgHdr.java b/services/net/java/android/net/netlink/StructNlMsgHdr.java
deleted file mode 100644
index 98ab5e7..0000000
--- a/services/net/java/android/net/netlink/StructNlMsgHdr.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlmsghdr
- *
- * see <linux_src>/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlMsgHdr {
- // Already aligned.
- public static final int STRUCT_SIZE = 16;
-
- public static final short NLM_F_REQUEST = 0x0001;
- public static final short NLM_F_MULTI = 0x0002;
- public static final short NLM_F_ACK = 0x0004;
- public static final short NLM_F_ECHO = 0x0008;
- // Flags for a GET request.
- public static final short NLM_F_ROOT = 0x0100;
- public static final short NLM_F_MATCH = 0x0200;
- public static final short NLM_F_DUMP = NLM_F_ROOT|NLM_F_MATCH;
- // Flags for a NEW request.
- public static final short NLM_F_REPLACE = 0x100;
- public static final short NLM_F_EXCL = 0x200;
- public static final short NLM_F_CREATE = 0x400;
- public static final short NLM_F_APPEND = 0x800;
-
-
- public static String stringForNlMsgFlags(short flags) {
- final StringBuilder sb = new StringBuilder();
- if ((flags & NLM_F_REQUEST) != 0) {
- sb.append("NLM_F_REQUEST");
- }
- if ((flags & NLM_F_MULTI) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NLM_F_MULTI");
- }
- if ((flags & NLM_F_ACK) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NLM_F_ACK");
- }
- if ((flags & NLM_F_ECHO) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NLM_F_ECHO");
- }
- if ((flags & NLM_F_ROOT) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NLM_F_ROOT");
- }
- if ((flags & NLM_F_MATCH) != 0) {
- if (sb.length() > 0) { sb.append("|"); }
- sb.append("NLM_F_MATCH");
- }
- return sb.toString();
- }
-
- public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
- return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
- }
-
- public static StructNlMsgHdr parse(ByteBuffer byteBuffer) {
- if (!hasAvailableSpace(byteBuffer)) { return null; }
-
- // The ByteOrder must have already been set by the caller. In most
- // cases ByteOrder.nativeOrder() is correct, with the exception
- // of usage within unittests.
- final StructNlMsgHdr struct = new StructNlMsgHdr();
- struct.nlmsg_len = byteBuffer.getInt();
- struct.nlmsg_type = byteBuffer.getShort();
- struct.nlmsg_flags = byteBuffer.getShort();
- struct.nlmsg_seq = byteBuffer.getInt();
- struct.nlmsg_pid = byteBuffer.getInt();
-
- if (struct.nlmsg_len < STRUCT_SIZE) {
- // Malformed.
- return null;
- }
- return struct;
- }
-
- public int nlmsg_len;
- public short nlmsg_type;
- public short nlmsg_flags;
- public int nlmsg_seq;
- public int nlmsg_pid;
-
- public StructNlMsgHdr() {
- nlmsg_len = 0;
- nlmsg_type = 0;
- nlmsg_flags = 0;
- nlmsg_seq = 0;
- nlmsg_pid = 0;
- }
-
- public void pack(ByteBuffer byteBuffer) {
- // The ByteOrder must have already been set by the caller. In most
- // cases ByteOrder.nativeOrder() is correct, with the possible
- // exception of usage within unittests.
- byteBuffer.putInt(nlmsg_len);
- byteBuffer.putShort(nlmsg_type);
- byteBuffer.putShort(nlmsg_flags);
- byteBuffer.putInt(nlmsg_seq);
- byteBuffer.putInt(nlmsg_pid);
- }
-
- @Override
- public String toString() {
- final String typeStr = "" + nlmsg_type
- + "(" + NetlinkConstants.stringForNlMsgType(nlmsg_type) + ")";
- final String flagsStr = "" + nlmsg_flags
- + "(" + stringForNlMsgFlags(nlmsg_flags) + ")";
- return "StructNlMsgHdr{ "
- + "nlmsg_len{" + nlmsg_len + "}, "
- + "nlmsg_type{" + typeStr + "}, "
- + "nlmsg_flags{" + flagsStr + ")}, "
- + "nlmsg_seq{" + nlmsg_seq + "}, "
- + "nlmsg_pid{" + nlmsg_pid + "} "
- + "}";
- }
-}
diff --git a/services/net/java/android/net/shared/InitialConfiguration.java b/services/net/java/android/net/shared/InitialConfiguration.java
deleted file mode 100644
index 007c8ca9..0000000
--- a/services/net/java/android/net/shared/InitialConfiguration.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import static android.net.shared.ParcelableUtil.fromParcelableArray;
-import static android.net.shared.ParcelableUtil.toParcelableArray;
-import static android.text.TextUtils.join;
-
-import android.net.InetAddresses;
-import android.net.InitialConfigurationParcelable;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.RouteInfo;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Predicate;
-
-/** @hide */
-public class InitialConfiguration {
- public final Set<LinkAddress> ipAddresses = new HashSet<>();
- public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
- public final Set<InetAddress> dnsServers = new HashSet<>();
-
- private static final int RFC6177_MIN_PREFIX_LENGTH = 48;
- private static final int RFC7421_PREFIX_LENGTH = 64;
-
- public static final InetAddress INET6_ANY = InetAddresses.parseNumericAddress("::");
-
- /**
- * Create a InitialConfiguration that is a copy of the specified configuration.
- */
- public static InitialConfiguration copy(InitialConfiguration config) {
- if (config == null) {
- return null;
- }
- InitialConfiguration configCopy = new InitialConfiguration();
- configCopy.ipAddresses.addAll(config.ipAddresses);
- configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
- configCopy.dnsServers.addAll(config.dnsServers);
- return configCopy;
- }
-
- @Override
- public String toString() {
- return String.format(
- "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s})",
- join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
- join(", ", dnsServers));
- }
-
- /**
- * Tests whether the contents of this IpConfiguration represent a valid configuration.
- */
- public boolean isValid() {
- if (ipAddresses.isEmpty()) {
- return false;
- }
-
- // For every IP address, there must be at least one prefix containing that address.
- for (LinkAddress addr : ipAddresses) {
- if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
- return false;
- }
- }
- // For every dns server, there must be at least one prefix containing that address.
- for (InetAddress addr : dnsServers) {
- if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
- return false;
- }
- }
- // All IPv6 LinkAddresses have an RFC7421-suitable prefix length
- // (read: compliant with RFC4291#section2.5.4).
- if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
- return false;
- }
- // If directlyConnectedRoutes contains an IPv6 default route
- // then ipAddresses MUST contain at least one non-ULA GUA.
- if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
- && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
- return false;
- }
- // The prefix length of routes in directlyConnectedRoutes be within reasonable
- // bounds for IPv6: /48-/64 just as we’d accept in RIOs.
- if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
- return false;
- }
- // There no more than one IPv4 address
- if (ipAddresses.stream().filter(InitialConfiguration::isIPv4).count() > 1) {
- return false;
- }
-
- return true;
- }
-
- /**
- * @return true if the given list of addressess and routes satisfies provisioning for this
- * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
- * because addresses and routes seen by Netlink will contain additional fields like flags,
- * interfaces, and so on. If this InitialConfiguration has no IP address specified, the
- * provisioning check always fails.
- *
- * If the given list of routes is null, only addresses are taken into considerations.
- */
- public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
- if (ipAddresses.isEmpty()) {
- return false;
- }
-
- for (LinkAddress addr : ipAddresses) {
- if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
- return false;
- }
- }
-
- if (routes != null) {
- for (IpPrefix prefix : directlyConnectedRoutes) {
- if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Convert this configuration to a {@link InitialConfigurationParcelable}.
- */
- public InitialConfigurationParcelable toStableParcelable() {
- final InitialConfigurationParcelable p = new InitialConfigurationParcelable();
- p.ipAddresses = ipAddresses.toArray(new LinkAddress[0]);
- p.directlyConnectedRoutes = directlyConnectedRoutes.toArray(new IpPrefix[0]);
- p.dnsServers = toParcelableArray(
- dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class);
- return p;
- }
-
- /**
- * Create an instance of {@link InitialConfiguration} based on the contents of the specified
- * {@link InitialConfigurationParcelable}.
- */
- public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) {
- if (p == null) return null;
- final InitialConfiguration config = new InitialConfiguration();
- config.ipAddresses.addAll(Arrays.asList(p.ipAddresses));
- config.directlyConnectedRoutes.addAll(Arrays.asList(p.directlyConnectedRoutes));
- config.dnsServers.addAll(
- fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress));
- return config;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof InitialConfiguration)) return false;
- final InitialConfiguration other = (InitialConfiguration) obj;
- return ipAddresses.equals(other.ipAddresses)
- && directlyConnectedRoutes.equals(other.directlyConnectedRoutes)
- && dnsServers.equals(other.dnsServers);
- }
-
- private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
- return !route.hasGateway() && prefix.equals(route.getDestination());
- }
-
- private static boolean isPrefixLengthCompliant(LinkAddress addr) {
- return isIPv4(addr) || isCompliantIPv6PrefixLength(addr.getPrefixLength());
- }
-
- private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
- return isIPv4(prefix) || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
- }
-
- private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
- return (RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
- && (prefixLength <= RFC7421_PREFIX_LENGTH);
- }
-
- private static boolean isIPv4(IpPrefix prefix) {
- return prefix.getAddress() instanceof Inet4Address;
- }
-
- private static boolean isIPv4(LinkAddress addr) {
- return addr.getAddress() instanceof Inet4Address;
- }
-
- private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
- return prefix.getAddress().equals(INET6_ANY);
- }
-
- private static boolean isIPv6GUA(LinkAddress addr) {
- return addr.isIpv6() && addr.isGlobalPreferred();
- }
-
- // TODO: extract out into CollectionUtils.
-
- /**
- * Indicate whether any element of the specified iterable verifies the specified predicate.
- */
- public static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
- for (T t : coll) {
- if (fn.test(t)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Indicate whether all elements of the specified iterable verifies the specified predicate.
- */
- public static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
- return !any(coll, not(fn));
- }
-
- /**
- * Create a predicate that returns the opposite value of the specified predicate.
- */
- public static <T> Predicate<T> not(Predicate<T> fn) {
- return (t) -> !fn.test(t);
- }
-}
diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
deleted file mode 100644
index 172dc24..0000000
--- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import android.annotation.Nullable;
-import android.net.DhcpResults;
-import android.net.DhcpResultsParcelable;
-import android.net.InetAddresses;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-
-/**
- * Collection of utility methods to convert to and from stable AIDL parcelables for IpClient
- * configuration classes.
- * @hide
- */
-public final class IpConfigurationParcelableUtil {
- /**
- * Convert DhcpResults to a DhcpResultsParcelable.
- */
- public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) {
- if (results == null) return null;
- final DhcpResultsParcelable p = new DhcpResultsParcelable();
- p.baseConfiguration = results.toStaticIpConfiguration();
- p.leaseDuration = results.leaseDuration;
- p.mtu = results.mtu;
- p.serverAddress = parcelAddress(results.serverAddress);
- p.vendorInfo = results.vendorInfo;
- p.serverHostName = results.serverHostName;
- return p;
- }
-
- /**
- * Convert a DhcpResultsParcelable to DhcpResults.
- */
- public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) {
- if (p == null) return null;
- final DhcpResults results = new DhcpResults(p.baseConfiguration);
- results.leaseDuration = p.leaseDuration;
- results.mtu = p.mtu;
- results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress);
- results.vendorInfo = p.vendorInfo;
- results.serverHostName = p.serverHostName;
- return results;
- }
-
- /**
- * Convert InetAddress to String.
- * TODO: have an InetAddressParcelable
- */
- public static String parcelAddress(@Nullable InetAddress addr) {
- if (addr == null) return null;
- return addr.getHostAddress();
- }
-
- /**
- * Convert String to InetAddress.
- * TODO: have an InetAddressParcelable
- */
- public static InetAddress unparcelAddress(@Nullable String addr) {
- if (addr == null) return null;
- return InetAddresses.parseNumericAddress(addr);
- }
-}
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
deleted file mode 100644
index 1729da6..0000000
--- a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import android.annotation.Nullable;
-import android.net.LinkProperties;
-import android.net.ProxyInfo;
-
-/**
- * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
- * and its attributes.
- * @hide
- */
-public final class LinkPropertiesParcelableUtil {
- // Temporary methods to facilitate migrating clients away from LinkPropertiesParcelable
- // TODO: remove the following methods after migrating clients.
-
- /**
- * @deprecated conversion to stable parcelable is no longer necessary.
- */
- @Deprecated
- public static LinkProperties toStableParcelable(@Nullable LinkProperties lp) {
- return lp;
- }
-
- /**
- * @deprecated conversion to stable parcelable is no longer necessary.
- */
- @Deprecated
- public static ProxyInfo toStableParcelable(@Nullable ProxyInfo info) {
- return info;
- }
-}
diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java
deleted file mode 100644
index 46e9c73..0000000
--- a/services/net/java/android/net/shared/NetworkMonitorUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 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.net.shared;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-
-import android.net.NetworkCapabilities;
-
-/** @hide */
-public class NetworkMonitorUtils {
-
- // Network conditions broadcast constants
- public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
- "android.net.conn.NETWORK_CONDITIONS_MEASURED";
- public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
- public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
- public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
- public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
- public static final String EXTRA_CELL_ID = "extra_cellid";
- public static final String EXTRA_SSID = "extra_ssid";
- public static final String EXTRA_BSSID = "extra_bssid";
- /** real time since boot */
- public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
- public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
- public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
- "android.permission.ACCESS_NETWORK_CONDITIONS";
-
- /**
- * Return whether validation is required for private DNS in strict mode.
- * @param nc Network capabilities of the network to test.
- */
- public static boolean isPrivateDnsValidationRequired(NetworkCapabilities nc) {
- // TODO: Consider requiring validation for DUN networks.
- return nc != null
- && nc.hasCapability(NET_CAPABILITY_INTERNET)
- && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
- && nc.hasCapability(NET_CAPABILITY_TRUSTED);
- }
-
- /**
- * Return whether validation is required for a network.
- * @param nc Network capabilities of the network to test.
- */
- public static boolean isValidationRequired(NetworkCapabilities nc) {
- // TODO: Consider requiring validation for DUN networks.
- return isPrivateDnsValidationRequired(nc) && nc.hasCapability(NET_CAPABILITY_NOT_VPN);
- }
-}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
deleted file mode 100644
index 3f40300..0000000
--- a/services/net/java/android/net/shared/ParcelableUtil.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import android.annotation.NonNull;
-
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.function.Function;
-
-/**
- * Utility methods to help convert to/from stable parcelables.
- * @hide
- */
-public final class ParcelableUtil {
- // Below methods could be implemented easily with streams, but streams are frowned upon in
- // frameworks code.
-
- /**
- * Convert a list of BaseType items to an array of ParcelableType items using the specified
- * converter function.
- */
- public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
- @NonNull Collection<BaseType> base,
- @NonNull Function<BaseType, ParcelableType> conv,
- @NonNull Class<ParcelableType> parcelClass) {
- final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
- int i = 0;
- for (BaseType b : base) {
- out[i] = conv.apply(b);
- i++;
- }
- return out;
- }
-
- /**
- * Convert an array of ParcelableType items to a list of BaseType items using the specified
- * converter function.
- */
- public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
- @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
- final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
- for (ParcelableType t : parceled) {
- out.add(conv.apply(t));
- }
- return out;
- }
-}
diff --git a/services/net/java/android/net/shared/PrivateDnsConfig.java b/services/net/java/android/net/shared/PrivateDnsConfig.java
deleted file mode 100644
index c7dc530..0000000
--- a/services/net/java/android/net/shared/PrivateDnsConfig.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2018 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.net.shared;
-
-import static android.net.shared.ParcelableUtil.fromParcelableArray;
-import static android.net.shared.ParcelableUtil.toParcelableArray;
-
-import android.net.PrivateDnsConfigParcel;
-import android.text.TextUtils;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-
-/** @hide */
-public class PrivateDnsConfig {
- public final boolean useTls;
- public final String hostname;
- public final InetAddress[] ips;
-
- public PrivateDnsConfig() {
- this(false);
- }
-
- public PrivateDnsConfig(boolean useTls) {
- this.useTls = useTls;
- this.hostname = "";
- this.ips = new InetAddress[0];
- }
-
- public PrivateDnsConfig(String hostname, InetAddress[] ips) {
- this.useTls = !TextUtils.isEmpty(hostname);
- this.hostname = useTls ? hostname : "";
- this.ips = (ips != null) ? ips : new InetAddress[0];
- }
-
- public PrivateDnsConfig(PrivateDnsConfig cfg) {
- useTls = cfg.useTls;
- hostname = cfg.hostname;
- ips = cfg.ips;
- }
-
- /**
- * Indicates whether this is a strict mode private DNS configuration.
- */
- public boolean inStrictMode() {
- return useTls && !TextUtils.isEmpty(hostname);
- }
-
- @Override
- public String toString() {
- return PrivateDnsConfig.class.getSimpleName()
- + "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
- }
-
- /**
- * Create a stable AIDL-compatible parcel from the current instance.
- */
- public PrivateDnsConfigParcel toParcel() {
- final PrivateDnsConfigParcel parcel = new PrivateDnsConfigParcel();
- parcel.hostname = hostname;
- parcel.ips = toParcelableArray(
- Arrays.asList(ips), IpConfigurationParcelableUtil::parcelAddress, String.class);
-
- return parcel;
- }
-
- /**
- * Build a configuration from a stable AIDL-compatible parcel.
- */
- public static PrivateDnsConfig fromParcel(PrivateDnsConfigParcel parcel) {
- InetAddress[] ips = new InetAddress[parcel.ips.length];
- ips = fromParcelableArray(parcel.ips, IpConfigurationParcelableUtil::unparcelAddress)
- .toArray(ips);
- return new PrivateDnsConfig(parcel.hostname, ips);
- }
-}
diff --git a/services/net/java/android/net/shared/ProvisioningConfiguration.java b/services/net/java/android/net/shared/ProvisioningConfiguration.java
deleted file mode 100644
index 6f9c294..0000000
--- a/services/net/java/android/net/shared/ProvisioningConfiguration.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import android.annotation.Nullable;
-import android.net.INetd;
-import android.net.Network;
-import android.net.ProvisioningConfigurationParcelable;
-import android.net.StaticIpConfiguration;
-import android.net.apf.ApfCapabilities;
-import android.net.ip.IIpClient;
-
-import java.util.Objects;
-import java.util.StringJoiner;
-
-/**
- * This class encapsulates parameters to be passed to
- * IpClient#startProvisioning(). A defensive copy is made by IpClient
- * and the values specified herein are in force until IpClient#stop()
- * is called.
- *
- * Example use:
- *
- * final ProvisioningConfiguration config =
- * new ProvisioningConfiguration.Builder()
- * .withPreDhcpAction()
- * .withProvisioningTimeoutMs(36 * 1000)
- * .build();
- * mIpClient.startProvisioning(config.toStableParcelable());
- * ...
- * mIpClient.stop();
- *
- * The specified provisioning configuration will only be active until
- * IIpClient#stop() is called. Future calls to IIpClient#startProvisioning()
- * must specify the configuration again.
- * @hide
- */
-public class ProvisioningConfiguration {
- // TODO: Delete this default timeout once those callers that care are
- // fixed to pass in their preferred timeout.
- //
- // We pick 36 seconds so we can send DHCP requests at
- //
- // t=0, t=2, t=6, t=14, t=30
- //
- // allowing for 10% jitter.
- private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
-
- /**
- * Builder to create a {@link ProvisioningConfiguration}.
- */
- public static class Builder {
- protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
-
- /**
- * Specify that the configuration should not enable IPv4. It is enabled by default.
- */
- public Builder withoutIPv4() {
- mConfig.mEnableIPv4 = false;
- return this;
- }
-
- /**
- * Specify that the configuration should not enable IPv6. It is enabled by default.
- */
- public Builder withoutIPv6() {
- mConfig.mEnableIPv6 = false;
- return this;
- }
-
- /**
- * Specify that the configuration should not use a MultinetworkPolicyTracker. It is used
- * by default.
- */
- public Builder withoutMultinetworkPolicyTracker() {
- mConfig.mUsingMultinetworkPolicyTracker = false;
- return this;
- }
-
- /**
- * Specify that the configuration should not use a IpReachabilityMonitor. It is used by
- * default.
- */
- public Builder withoutIpReachabilityMonitor() {
- mConfig.mUsingIpReachabilityMonitor = false;
- return this;
- }
-
- /**
- * Identical to {@link #withPreDhcpAction(int)}, using a default timeout.
- * @see #withPreDhcpAction(int)
- */
- public Builder withPreDhcpAction() {
- mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
- return this;
- }
-
- /**
- * Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must
- * call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior
- * is disabled by default.
- * @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction().
- */
- public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
- mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
- return this;
- }
-
- /**
- * Specify the initial provisioning configuration.
- */
- public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
- mConfig.mInitialConfig = initialConfig;
- return this;
- }
-
- /**
- * Specify a static configuration for provisioning.
- */
- public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
- mConfig.mStaticIpConfig = staticConfig;
- return this;
- }
-
- /**
- * Specify ApfCapabilities.
- */
- public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
- mConfig.mApfCapabilities = apfCapabilities;
- return this;
- }
-
- /**
- * Specify the timeout to use for provisioning.
- */
- public Builder withProvisioningTimeoutMs(int timeoutMs) {
- mConfig.mProvisioningTimeoutMs = timeoutMs;
- return this;
- }
-
- /**
- * Specify that IPv6 address generation should use a random MAC address.
- */
- public Builder withRandomMacAddress() {
- mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
- return this;
- }
-
- /**
- * Specify that IPv6 address generation should use a stable MAC address.
- */
- public Builder withStableMacAddress() {
- mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
- return this;
- }
-
- /**
- * Specify the network to use for provisioning.
- */
- public Builder withNetwork(Network network) {
- mConfig.mNetwork = network;
- return this;
- }
-
- /**
- * Specify the display name that the IpClient should use.
- */
- public Builder withDisplayName(String displayName) {
- mConfig.mDisplayName = displayName;
- return this;
- }
-
- /**
- * Build the configuration using previously specified parameters.
- */
- public ProvisioningConfiguration build() {
- return new ProvisioningConfiguration(mConfig);
- }
- }
-
- public boolean mEnableIPv4 = true;
- public boolean mEnableIPv6 = true;
- public boolean mUsingMultinetworkPolicyTracker = true;
- public boolean mUsingIpReachabilityMonitor = true;
- public int mRequestedPreDhcpActionMs;
- public InitialConfiguration mInitialConfig;
- public StaticIpConfiguration mStaticIpConfig;
- public ApfCapabilities mApfCapabilities;
- public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
- public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
- public Network mNetwork = null;
- public String mDisplayName = null;
-
- public ProvisioningConfiguration() {} // used by Builder
-
- public ProvisioningConfiguration(ProvisioningConfiguration other) {
- mEnableIPv4 = other.mEnableIPv4;
- mEnableIPv6 = other.mEnableIPv6;
- mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
- mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
- mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
- mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
- mStaticIpConfig = other.mStaticIpConfig == null
- ? null
- : new StaticIpConfiguration(other.mStaticIpConfig);
- mApfCapabilities = other.mApfCapabilities;
- mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
- mIPv6AddrGenMode = other.mIPv6AddrGenMode;
- mNetwork = other.mNetwork;
- mDisplayName = other.mDisplayName;
- }
-
- /**
- * Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration.
- */
- public ProvisioningConfigurationParcelable toStableParcelable() {
- final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
- p.enableIPv4 = mEnableIPv4;
- p.enableIPv6 = mEnableIPv6;
- p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker;
- p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor;
- p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs;
- p.initialConfig = mInitialConfig == null ? null : mInitialConfig.toStableParcelable();
- p.staticIpConfig = mStaticIpConfig == null
- ? null
- : new StaticIpConfiguration(mStaticIpConfig);
- p.apfCapabilities = mApfCapabilities; // ApfCapabilities is immutable
- p.provisioningTimeoutMs = mProvisioningTimeoutMs;
- p.ipv6AddrGenMode = mIPv6AddrGenMode;
- p.network = mNetwork;
- p.displayName = mDisplayName;
- return p;
- }
-
- /**
- * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable.
- */
- public static ProvisioningConfiguration fromStableParcelable(
- @Nullable ProvisioningConfigurationParcelable p) {
- if (p == null) return null;
- final ProvisioningConfiguration config = new ProvisioningConfiguration();
- config.mEnableIPv4 = p.enableIPv4;
- config.mEnableIPv6 = p.enableIPv6;
- config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker;
- config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor;
- config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs;
- config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig);
- config.mStaticIpConfig = p.staticIpConfig == null
- ? null
- : new StaticIpConfiguration(p.staticIpConfig);
- config.mApfCapabilities = p.apfCapabilities; // ApfCapabilities is immutable
- config.mProvisioningTimeoutMs = p.provisioningTimeoutMs;
- config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
- config.mNetwork = p.network;
- config.mDisplayName = p.displayName;
- return config;
- }
-
- @Override
- public String toString() {
- return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
- .add("mEnableIPv4: " + mEnableIPv4)
- .add("mEnableIPv6: " + mEnableIPv6)
- .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
- .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
- .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
- .add("mInitialConfig: " + mInitialConfig)
- .add("mStaticIpConfig: " + mStaticIpConfig)
- .add("mApfCapabilities: " + mApfCapabilities)
- .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
- .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
- .add("mNetwork: " + mNetwork)
- .add("mDisplayName: " + mDisplayName)
- .toString();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof ProvisioningConfiguration)) return false;
- final ProvisioningConfiguration other = (ProvisioningConfiguration) obj;
- return mEnableIPv4 == other.mEnableIPv4
- && mEnableIPv6 == other.mEnableIPv6
- && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker
- && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor
- && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs
- && Objects.equals(mInitialConfig, other.mInitialConfig)
- && Objects.equals(mStaticIpConfig, other.mStaticIpConfig)
- && Objects.equals(mApfCapabilities, other.mApfCapabilities)
- && mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
- && mIPv6AddrGenMode == other.mIPv6AddrGenMode
- && Objects.equals(mNetwork, other.mNetwork)
- && Objects.equals(mDisplayName, other.mDisplayName);
- }
-
- public boolean isValid() {
- return (mInitialConfig == null) || mInitialConfig.isValid();
- }
-}
diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java
deleted file mode 100644
index f6bb873..0000000
--- a/services/net/java/android/net/util/InterfaceParams.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.net.util;
-
-import static com.android.internal.util.Preconditions.checkArgument;
-
-import android.net.MacAddress;
-import android.text.TextUtils;
-
-import java.net.NetworkInterface;
-import java.net.SocketException;
-
-
-/**
- * Encapsulate the interface parameters common to IpClient/IpServer components.
- *
- * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient
- * and IpServer (sub)components need most or all of this information at some
- * point during their lifecycles, so pass only this simplified object around
- * which can be created once when IpClient/IpServer are told to start.
- *
- * @hide
- */
-public class InterfaceParams {
- public final String name;
- public final int index;
- public final MacAddress macAddr;
- public final int defaultMtu;
-
- // TODO: move the below to NetworkStackConstants when this class is moved to the NetworkStack.
- private static final int ETHER_MTU = 1500;
- private static final int IPV6_MIN_MTU = 1280;
-
-
- public static InterfaceParams getByName(String name) {
- final NetworkInterface netif = getNetworkInterfaceByName(name);
- if (netif == null) return null;
-
- // Not all interfaces have MAC addresses, e.g. rmnet_data0.
- final MacAddress macAddr = getMacAddress(netif);
-
- try {
- return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU());
- } catch (IllegalArgumentException|SocketException e) {
- return null;
- }
- }
-
- public InterfaceParams(String name, int index, MacAddress macAddr) {
- this(name, index, macAddr, ETHER_MTU);
- }
-
- public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) {
- checkArgument((!TextUtils.isEmpty(name)), "impossible interface name");
- checkArgument((index > 0), "invalid interface index");
- this.name = name;
- this.index = index;
- this.macAddr = (macAddr != null) ? macAddr : MacAddress.fromBytes(new byte[] {
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 });
- this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU;
- }
-
- @Override
- public String toString() {
- return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu);
- }
-
- private static NetworkInterface getNetworkInterfaceByName(String name) {
- try {
- return NetworkInterface.getByName(name);
- } catch (NullPointerException|SocketException e) {
- return null;
- }
- }
-
- private static MacAddress getMacAddress(NetworkInterface netif) {
- try {
- return MacAddress.fromBytes(netif.getHardwareAddress());
- } catch (IllegalArgumentException|NullPointerException|SocketException e) {
- return null;
- }
- }
-}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
deleted file mode 100644
index 2cdb2b0..0000000
--- a/services/net/java/android/net/util/SharedLog.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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.net.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.StringJoiner;
-
-
-/**
- * Class to centralize logging functionality for tethering.
- *
- * All access to class methods other than dump() must be on the same thread.
- *
- * TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated.
- * @hide
- */
-public class SharedLog {
- private static final int DEFAULT_MAX_RECORDS = 500;
- private static final String COMPONENT_DELIMITER = ".";
-
- private enum Category {
- NONE,
- ERROR,
- MARK,
- WARN,
- };
-
- private final LocalLog mLocalLog;
- // The tag to use for output to the system log. This is not output to the
- // LocalLog because that would be redundant.
- private final String mTag;
- // The component (or subcomponent) of a system that is sharing this log.
- // This can grow in depth if components call forSubComponent() to obtain
- // their SharedLog instance. The tag is not included in the component for
- // brevity.
- private final String mComponent;
-
- public SharedLog(String tag) {
- this(DEFAULT_MAX_RECORDS, tag);
- }
-
- public SharedLog(int maxRecords, String tag) {
- this(new LocalLog(maxRecords), tag, tag);
- }
-
- private SharedLog(LocalLog localLog, String tag, String component) {
- mLocalLog = localLog;
- mTag = tag;
- mComponent = component;
- }
-
- public String getTag() {
- return mTag;
- }
-
- /**
- * Create a SharedLog based on this log with an additional component prefix on each logged line.
- */
- public SharedLog forSubComponent(String component) {
- if (!isRootLogInstance()) {
- component = mComponent + COMPONENT_DELIMITER + component;
- }
- return new SharedLog(mLocalLog, mTag, component);
- }
-
- /**
- * Dump the contents of this log.
- *
- * <p>This method may be called on any thread.
- */
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
- }
-
- //////
- // Methods that both log an entry and emit it to the system log.
- //////
-
- /**
- * Log an error due to an exception. This does not include the exception stacktrace.
- *
- * <p>The log entry will be also added to the system log.
- * @see #e(String, Throwable)
- */
- public void e(Exception e) {
- Log.e(mTag, record(Category.ERROR, e.toString()));
- }
-
- /**
- * Log an error message.
- *
- * <p>The log entry will be also added to the system log.
- */
- public void e(String msg) {
- Log.e(mTag, record(Category.ERROR, msg));
- }
-
- /**
- * Log an error due to an exception, with the exception stacktrace if provided.
- *
- * <p>The error and exception message appear in the shared log, but the stacktrace is only
- * logged in general log output (logcat). The log entry will be also added to the system log.
- */
- public void e(@NonNull String msg, @Nullable Throwable exception) {
- if (exception == null) {
- e(msg);
- return;
- }
- Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
- }
-
- /**
- * Log an informational message.
- *
- * <p>The log entry will be also added to the system log.
- */
- public void i(String msg) {
- Log.i(mTag, record(Category.NONE, msg));
- }
-
- /**
- * Log a warning message.
- *
- * <p>The log entry will be also added to the system log.
- */
- public void w(String msg) {
- Log.w(mTag, record(Category.WARN, msg));
- }
-
- //////
- // Methods that only log an entry (and do NOT emit to the system log).
- //////
-
- /**
- * Log a general message to be only included in the in-memory log.
- *
- * <p>The log entry will *not* be added to the system log.
- */
- public void log(String msg) {
- record(Category.NONE, msg);
- }
-
- /**
- * Log a general, formatted message to be only included in the in-memory log.
- *
- * <p>The log entry will *not* be added to the system log.
- * @see String#format(String, Object...)
- */
- public void logf(String fmt, Object... args) {
- log(String.format(fmt, args));
- }
-
- /**
- * Log a message with MARK level.
- *
- * <p>The log entry will *not* be added to the system log.
- */
- public void mark(String msg) {
- record(Category.MARK, msg);
- }
-
- private String record(Category category, String msg) {
- final String entry = logLine(category, msg);
- mLocalLog.log(entry);
- return entry;
- }
-
- private String logLine(Category category, String msg) {
- final StringJoiner sj = new StringJoiner(" ");
- if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
- if (category != Category.NONE) sj.add(category.toString());
- return sj.add(msg).toString();
- }
-
- // Check whether this SharedLog instance is nominally the top level in
- // a potential hierarchy of shared logs (the root of a tree),
- // or is a subcomponent within the hierarchy.
- private boolean isRootLogInstance() {
- return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index e9e96c9..8fd8d04 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -56,6 +56,7 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
import android.net.wifi.WifiSsid;
import android.os.Binder;
import android.os.Handler;
@@ -719,7 +720,7 @@
@Test
public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_noneSsid() throws Exception {
- when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
+ when(mWifiInfo.getSSID()).thenReturn(WifiManager.UNKNOWN_SSID);
NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
@@ -793,7 +794,7 @@
List<ScanResult> invalidScanResults = Lists.newArrayList(
new ScanResult(),
createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid),
- createScanResult(WifiSsid.NONE, SCORED_NETWORK.networkKey.wifiKey.bssid),
+ createScanResult(WifiManager.UNKNOWN_SSID, SCORED_NETWORK.networkKey.wifiKey.bssid),
createScanResult(SSID, null),
createScanResult(SSID, INVALID_BSSID)
);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
new file mode 100644
index 0000000..470d4fa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.content.pm.PackageParser;
+
+import com.android.internal.util.ArrayUtils;
+
+class PackageBuilder {
+ final PackageParser.Package mPkg;
+
+ PackageBuilder(String packageName) {
+ mPkg = new PackageParser.Package(packageName);
+ }
+
+ PackageBuilder setApplicationInfoCodePath(String codePath) {
+ mPkg.applicationInfo.setCodePath(codePath);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
+ mPkg.applicationInfo.setResourcePath(resourcePath);
+ return this;
+ }
+
+ PackageBuilder setCodePath(String codePath) {
+ mPkg.codePath = codePath;
+ return this;
+ }
+
+ PackageBuilder setBaseCodePath(String baseCodePath) {
+ mPkg.baseCodePath = baseCodePath;
+ return this;
+ }
+
+ PackageBuilder addUsesStaticLibrary(String name, long version) {
+ mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
+ mPkg.usesStaticLibrariesVersions =
+ ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
+ mPkg.applicationInfo.nativeLibraryRootDir = dir;
+ return this;
+ }
+
+ PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
+ mPkg.staticSharedLibVersion = staticSharedLibVersion;
+ mPkg.staticSharedLibName = staticSharedLibName;
+ return this;
+ }
+
+ PackageBuilder setManifestPackageName(String manifestPackageName) {
+ mPkg.manifestPackageName = manifestPackageName;
+ return this;
+ }
+
+ PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
+ mPkg.mVersionCodeMajor = versionCodeMajor;
+ return this;
+ }
+
+ PackageBuilder setVersionCode(int versionCode) {
+ mPkg.mVersionCode = versionCode;
+ return this;
+ }
+
+ PackageBuilder addSplitCodePath(String splitCodePath) {
+ mPkg.splitCodePaths =
+ ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
+ mPkg.applicationInfo.volumeUuid = volumeUuid;
+ return this;
+ }
+
+ PackageBuilder addLibraryName(String libraryName) {
+ mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
+ return this;
+ }
+
+ PackageBuilder setRealPackageName(String realPackageName) {
+ mPkg.mRealPackage = realPackageName;
+ return this;
+ }
+
+ PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
+ mPkg.cpuAbiOverride = cpuAbiOverride;
+ return this;
+ }
+
+ PackageBuilder addPermissionRequest(String permissionName) {
+ mPkg.requestedPermissions.add(permissionName);
+ return this;
+ }
+
+ PackageParser.Package build() {
+ return mPkg;
+ }
+
+ public PackageBuilder addApplicationInfoFlag(int flag) {
+ mPkg.applicationInfo.flags |= flag;
+ return this;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
new file mode 100644
index 0000000..b42cfd8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.content.pm.PackageUserState;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.util.List;
+
+class PackageSettingBuilder {
+ private String mName;
+ private String mRealName;
+ private String mCodePath;
+ private String mResourcePath;
+ private String mLegacyNativeLibraryPathString;
+ private String mPrimaryCpuAbiString;
+ private String mSecondaryCpuAbiString;
+ private String mCpuAbiOverrideString;
+ private long mPVersionCode;
+ private int mPkgFlags;
+ private int mPrivateFlags;
+ private String mParentPackageName;
+ private List<String> mChildPackageNames;
+ private int mSharedUserId;
+ private String[] mUsesStaticLibraries;
+ private long[] mUsesStaticLibrariesVersions;
+ private String mVolumeUuid;
+ private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+
+ public PackageSettingBuilder setName(String name) {
+ this.mName = name;
+ return this;
+ }
+
+ public PackageSettingBuilder setRealName(String realName) {
+ this.mRealName = realName;
+ return this;
+ }
+
+ public PackageSettingBuilder setCodePath(String codePath) {
+ this.mCodePath = codePath;
+ return this;
+ }
+
+ public PackageSettingBuilder setResourcePath(String resourcePath) {
+ this.mResourcePath = resourcePath;
+ return this;
+ }
+
+ public PackageSettingBuilder setLegacyNativeLibraryPathString(
+ String legacyNativeLibraryPathString) {
+ this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
+ return this;
+ }
+
+ public PackageSettingBuilder setPrimaryCpuAbiString(String primaryCpuAbiString) {
+ this.mPrimaryCpuAbiString = primaryCpuAbiString;
+ return this;
+ }
+
+ public PackageSettingBuilder setSecondaryCpuAbiString(String secondaryCpuAbiString) {
+ this.mSecondaryCpuAbiString = secondaryCpuAbiString;
+ return this;
+ }
+
+ public PackageSettingBuilder setCpuAbiOverrideString(String cpuAbiOverrideString) {
+ this.mCpuAbiOverrideString = cpuAbiOverrideString;
+ return this;
+ }
+
+ public PackageSettingBuilder setPVersionCode(long pVersionCode) {
+ this.mPVersionCode = pVersionCode;
+ return this;
+ }
+
+ public PackageSettingBuilder setPkgFlags(int pkgFlags) {
+ this.mPkgFlags = pkgFlags;
+ return this;
+ }
+
+ public PackageSettingBuilder setPrivateFlags(int privateFlags) {
+ this.mPrivateFlags = privateFlags;
+ return this;
+ }
+
+ public PackageSettingBuilder setParentPackageName(String parentPackageName) {
+ this.mParentPackageName = parentPackageName;
+ return this;
+ }
+
+ public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
+ this.mChildPackageNames = childPackageNames;
+ return this;
+ }
+
+ public PackageSettingBuilder setSharedUserId(int sharedUserId) {
+ this.mSharedUserId = sharedUserId;
+ return this;
+ }
+
+ public PackageSettingBuilder setUsesStaticLibraries(String[] usesStaticLibraries) {
+ this.mUsesStaticLibraries = usesStaticLibraries;
+ return this;
+ }
+
+ public PackageSettingBuilder setUsesStaticLibrariesVersions(
+ long[] usesStaticLibrariesVersions) {
+ this.mUsesStaticLibrariesVersions = usesStaticLibrariesVersions;
+ return this;
+ }
+
+ public PackageSettingBuilder setVolumeUuid(String volumeUuid) {
+ this.mVolumeUuid = volumeUuid;
+ return this;
+ }
+
+ public PackageSettingBuilder setInstantAppUserState(int userId, boolean isInstant) {
+ if (mUserStates.indexOfKey(userId) < 0) {
+ mUserStates.put(userId, new PackageUserState());
+ }
+ mUserStates.get(userId).instantApp = isInstant;
+ return this;
+ }
+
+ public PackageSetting build() {
+ final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
+ new File(mCodePath), new File(mResourcePath),
+ mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
+ mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
+ mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
+ mUsesStaticLibrariesVersions);
+ packageSetting.volumeUuid = this.mVolumeUuid;
+ for (int i = 0; i < mUserStates.size(); i++) {
+ packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
+ }
+ return packageSetting;
+
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
new file mode 100644
index 0000000..34a3f86
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.content.pm.PackageParser;
+import android.os.UserHandle;
+
+class ScanRequestBuilder {
+ private final PackageParser.Package mPkg;
+ private PackageParser.Package mOldPkg;
+ private SharedUserSetting mSharedUserSetting;
+ private PackageSetting mPkgSetting;
+ private PackageSetting mDisabledPkgSetting;
+ private PackageSetting mOriginalPkgSetting;
+ private String mRealPkgName;
+ private int mParseFlags;
+ private int mScanFlags;
+ private UserHandle mUser;
+ private boolean mIsPlatformPackage;
+
+ ScanRequestBuilder(PackageParser.Package pkg) {
+ this.mPkg = pkg;
+ }
+
+ public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+ this.mOldPkg = oldPkg;
+ return this;
+ }
+
+ public ScanRequestBuilder setSharedUserSetting(SharedUserSetting sharedUserSetting) {
+ this.mSharedUserSetting = sharedUserSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setPkgSetting(PackageSetting pkgSetting) {
+ this.mPkgSetting = pkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setDisabledPkgSetting(PackageSetting disabledPkgSetting) {
+ this.mDisabledPkgSetting = disabledPkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setOriginalPkgSetting(PackageSetting originalPkgSetting) {
+ this.mOriginalPkgSetting = originalPkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setRealPkgName(String realPkgName) {
+ this.mRealPkgName = realPkgName;
+ return this;
+ }
+
+ public ScanRequestBuilder setParseFlags(int parseFlags) {
+ this.mParseFlags = parseFlags;
+ return this;
+ }
+
+ public ScanRequestBuilder addParseFlag(int parseFlag) {
+ this.mParseFlags |= parseFlag;
+ return this;
+ }
+
+ public ScanRequestBuilder setScanFlags(int scanFlags) {
+ this.mScanFlags = scanFlags;
+ return this;
+ }
+
+ public ScanRequestBuilder addScanFlag(int scanFlag) {
+ this.mScanFlags |= scanFlag;
+ return this;
+ }
+
+ public ScanRequestBuilder setUser(UserHandle user) {
+ this.mUser = user;
+ return this;
+ }
+
+ public ScanRequestBuilder setIsPlatformPackage(boolean isPlatformPackage) {
+ this.mIsPlatformPackage = isPlatformPackage;
+ return this;
+ }
+
+ PackageManagerService.ScanRequest build() {
+ return new PackageManagerService.ScanRequest(
+ mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
+ mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
+ mUser);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
new file mode 100644
index 0000000..dd3d8b9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import static android.content.pm.SharedLibraryInfo.TYPE_DYNAMIC;
+import static android.content.pm.SharedLibraryInfo.TYPE_STATIC;
+import static android.content.pm.SharedLibraryInfo.VERSION_UNDEFINED;
+
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
+import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertNotSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
+import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+
+@RunWith(MockitoJUnitRunner.class)
+@Presubmit
+// TODO: shared user tests
+public class ScanTests {
+
+ private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
+
+ @Mock
+ PackageAbiHelper mMockPackageAbiHelper;
+ @Mock
+ UserManagerInternal mMockUserManager;
+
+ @Before
+ public void setupDefaultUser() {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+ }
+
+ @Before
+ public void setupDefaultAbiBehavior() throws Exception {
+ when(mMockPackageAbiHelper.derivePackageAbi(
+ any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
+ .thenReturn(new Pair<>(
+ new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
+ new PackageAbiHelper.NativeLibraryPaths(
+ "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
+ when(mMockPackageAbiHelper.getNativeLibraryPaths(
+ any(PackageParser.Package.class), any(File.class)))
+ .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
+ "getRootDir", true, "getNativeDir", "getNativeDir2"
+ ));
+ when(mMockPackageAbiHelper.getBundledAppAbis(
+ any(PackageParser.Package.class)))
+ .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
+ }
+
+ @Test
+ public void newInstallSimpleAllNominal() throws Exception {
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+ assertThat(scanResult.existingSettingCopied, is(false));
+ assertPathsNotDerived(scanResult);
+ }
+
+ @Test
+ public void newInstallForAllUsers() throws Exception {
+ final int[] userIds = {0, 10, 11};
+ when(mMockUserManager.getUserIds()).thenReturn(userIds);
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setRealPkgName(null)
+ .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .build();
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ for (int uid : userIds) {
+ assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
+ }
+ }
+
+ @Test
+ public void installRealPackageName() throws Exception {
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setRealPkgName("com.package.real")
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
+
+ final PackageManagerService.ScanRequest scanRequestNoRealPkg =
+ createBasicScanRequestBuilder(
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setRealPackageName("com.package.real").build())
+ .build();
+
+ final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
+ assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
+ }
+
+ @Test
+ public void updateSimpleNominal() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setPrimaryCpuAbiString("primaryCpuAbi")
+ .setSecondaryCpuAbiString("secondaryCpuAbi")
+ .build();
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .setPkgSetting(pkgSetting)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.existingSettingCopied, is(true));
+
+ // ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
+ assertNotSame(pkgSetting, scanResult.pkgSetting);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+
+ assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
+ assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
+ assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
+
+ assertPathsNotDerived(scanResult);
+ }
+
+ @Test
+ public void updateInstantSimpleNominal() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, true)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+ }
+
+ @Test
+ public void installStaticSharedLibrary() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
+ .setStaticSharedLib("static.lib", 123L)
+ .setManifestPackageName("static.lib.pkg")
+ .setVersionCodeMajor(1)
+ .setVersionCode(234)
+ .setBaseCodePath("/some/path.apk")
+ .addSplitCodePath("/some/other/path.apk")
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
+ pkg).setUser(UserHandle.of(0)).build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
+ assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
+ assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
+ assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
+ assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
+ is("static.lib.pkg"));
+ assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
+ assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
+ }
+
+ @Test
+ public void installDynamicLibraries() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
+ .setManifestPackageName("dynamic.lib.pkg")
+ .addLibraryName("liba")
+ .addLibraryName("libb")
+ .setVersionCodeMajor(1)
+ .setVersionCode(234)
+ .setBaseCodePath("/some/path.apk")
+ .addSplitCodePath("/some/other/path.apk")
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
+ assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib0.getName(), is("liba"));
+ assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
+ assertThat(dynamicLib0.getType(), is(TYPE_DYNAMIC));
+ assertThat(dynamicLib0.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib0.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(dynamicLib0.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(dynamicLib0.getDependencies(), nullValue());
+ assertThat(dynamicLib0.getDependentPackages(), empty());
+
+ final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
+ assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib1.getName(), is("libb"));
+ assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
+ assertThat(dynamicLib1.getType(), is(TYPE_DYNAMIC));
+ assertThat(dynamicLib1.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib1.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(dynamicLib1.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(dynamicLib1.getDependencies(), nullValue());
+ assertThat(dynamicLib1.getDependentPackages(), empty());
+ }
+
+ @Test
+ public void volumeUuidChangesOnUpdate() throws Exception {
+ final PackageSetting pkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setVolumeUuid("someUuid")
+ .build();
+
+ final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setApplicationInfoVolumeUuid("someNewUuid")
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(
+ new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
+
+ assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+ }
+
+ @Test
+ public void scanFirstBoot_derivesAbis() throws Exception {
+ final PackageSetting pkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
+
+ final PackageParser.Package basicPackage =
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setCpuAbiOVerride("testOverride")
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
+ basicPackage)
+ .setPkgSetting(pkgSetting)
+ .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
+ .build());
+
+ assertAbiAndPathssDerived(scanResult);
+ }
+
+ @Test
+ public void scanWithOriginalPkgSetting_packageNameChanges() throws Exception {
+ final PackageSetting originalPkgSetting =
+ createBasicPackageSettingBuilder("original.package").build();
+
+ final PackageParser.Package basicPackage =
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .build();
+
+
+ final PackageManagerService.ScanResult result =
+ executeScan(new ScanRequestBuilder(basicPackage)
+ .setOriginalPkgSetting(originalPkgSetting)
+ .build());
+
+ assertThat(result.request.pkg.packageName, is("original.package"));
+ }
+
+ @Test
+ public void updateInstant_changeToFull() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, true)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_AS_FULL_APP)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+ }
+
+ @Test
+ public void updateFull_changeToInstant() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, false)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_AS_INSTANT_APP)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+ }
+
+ @Test
+ public void updateSystemApp_applicationInfoFlagSet() throws Exception {
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .setDisabledPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_NEW_INSTALL)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.request.pkg.applicationInfo.flags,
+ hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
+ }
+
+ @Test
+ public void factoryTestFlagSet() throws Exception {
+ final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .addPermissionRequest(Manifest.permission.FACTORY_TEST)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+ createBasicScanRequestBuilder(basicPackage).build(),
+ new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+ true /*isUnderFactoryTest*/,
+ System.currentTimeMillis());
+
+ assertThat(scanResult.request.pkg.applicationInfo.flags,
+ hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
+ }
+
+ @Test
+ public void scanSystemApp_isOrphanedTrue() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(pkg)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.pkgSetting.isOrphaned, is(true));
+ }
+
+ private static Matcher<Integer> hasFlag(final int flag) {
+ return new BaseMatcher<Integer>() {
+ @Override public void describeTo(Description description) {
+ description.appendText("flags ");
+ }
+
+ @Override public boolean matches(Object item) {
+ return ((int) item & flag) != 0;
+ }
+
+ @Override
+ public void describeMismatch(Object item, Description mismatchDescription) {
+ mismatchDescription
+ .appendValue(item)
+ .appendText(" does not contain flag ")
+ .appendValue(flag);
+ }
+ };
+ }
+
+ private PackageManagerService.ScanResult executeScan(
+ PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
+ return PackageManagerService.scanPackageOnlyLI(
+ scanRequest,
+ new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+ false /*isUnderFactoryTest*/,
+ System.currentTimeMillis());
+ }
+
+ private static String createResourcePath(String packageName) {
+ return "/data/app/" + packageName + "-randompath/base.apk";
+ }
+
+ private static String createCodePath(String packageName) {
+ return "/data/app/" + packageName + "-randompath";
+ }
+
+ private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
+ return new PackageSettingBuilder()
+ .setName(packageName)
+ .setCodePath(createCodePath(packageName))
+ .setResourcePath(createResourcePath(packageName));
+ }
+
+ private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
+ return new ScanRequestBuilder(pkg)
+ .setUser(UserHandle.of(0));
+ }
+
+
+ private static PackageBuilder createBasicPackage(String packageName) {
+ return new PackageBuilder(packageName)
+ .setCodePath("/data/tmp/randompath")
+ .setApplicationInfoCodePath(createCodePath(packageName))
+ .setApplicationInfoResourcePath(createResourcePath(packageName))
+ .setApplicationInfoVolumeUuid("volumeUuid")
+ .setBaseCodePath("/data/tmp/randompath/base.apk")
+ .addUsesStaticLibrary("some.static.library", 234L)
+ .addUsesStaticLibrary("some.other.static.library", 456L)
+ .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+ .setVersionCodeMajor(1)
+ .setVersionCode(2345);
+ }
+
+ private static void assertBasicPackageScanResult(
+ PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
+ assertThat(scanResult.success, is(true));
+
+ final PackageSetting pkgSetting = scanResult.pkgSetting;
+ assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
+
+ final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+ assertBasicApplicationInfo(scanResult, applicationInfo);
+
+ }
+
+ private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
+ String packageName, boolean isInstant, PackageSetting pkgSetting) {
+ assertThat(pkgSetting.pkg.packageName, is(packageName));
+ assertThat(pkgSetting.getInstantApp(0), is(isInstant));
+ assertThat(pkgSetting.usesStaticLibraries,
+ arrayContaining("some.static.library", "some.other.static.library"));
+ assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
+ assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
+ assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
+ assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
+ assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
+ assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
+ }
+
+ private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
+ ApplicationInfo applicationInfo) {
+ assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+
+ final int uid = applicationInfo.uid;
+ assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
+
+ final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
+ applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
+ scanResult.request.pkg.packageName).getAbsolutePath();
+ assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
+ assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
+ }
+
+ private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
+ final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+ assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
+ assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
+
+ assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
+ assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
+ assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+ assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
+ assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
+ }
+
+ private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
+ final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+ assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
+ assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
+ assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+ assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
+ assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
new file mode 100644
index 0000000..1f312bf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 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.recoverysystem;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IRecoverySystemProgressListener;
+import android.os.Looper;
+import android.os.PowerManager;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileWriter;
+
+/**
+ * atest FrameworksServicesTests:RecoverySystemServiceTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecoverySystemServiceTest {
+ private RecoverySystemService mRecoverySystemService;
+ private RecoverySystemServiceTestable.FakeSystemProperties mSystemProperties;
+ private RecoverySystemService.UncryptSocket mUncryptSocket;
+ private Context mContext;
+ private IPowerManager mIPowerManager;
+ private FileWriter mUncryptUpdateFileWriter;
+
+ @Before
+ public void setup() {
+ mContext = mock(Context.class);
+ mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
+ mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
+ mUncryptUpdateFileWriter = mock(FileWriter.class);
+
+ Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+ mIPowerManager = mock(IPowerManager.class);
+ PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
+ new Handler(looper));
+
+ mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
+ powerManager, mUncryptUpdateFileWriter, mUncryptSocket);
+ }
+
+ @Test
+ public void clearBcb_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+ assertThat(mRecoverySystemService.clearBcb(), is(true));
+
+ assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test
+ public void clearBcb_uncrypt_failure() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+ assertThat(mRecoverySystemService.clearBcb(), is(false));
+
+ assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test(expected = SecurityException.class)
+ public void clearBcb_noPerm() {
+ doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ mRecoverySystemService.clearBcb();
+ }
+
+ @Test
+ public void setupBcb_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+ assertThat(mRecoverySystemService.setupBcb("foo"), is(true));
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test
+ public void setupBcb_uncrypt_failure() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+ assertThat(mRecoverySystemService.setupBcb("foo"), is(false));
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test(expected = SecurityException.class)
+ public void setupBcb_noPerm() {
+ doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ mRecoverySystemService.setupBcb("foo");
+ }
+
+ @Test
+ public void rebootRecoveryWithCommand_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+ mRecoverySystemService.rebootRecoveryWithCommand("foo");
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ verify(mIPowerManager).reboot(anyBoolean(), eq("recovery"), anyBoolean());
+ }
+
+ @Test
+ public void rebootRecoveryWithCommand_failure() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+ mRecoverySystemService.rebootRecoveryWithCommand("foo");
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ verifyNoMoreInteractions(mIPowerManager);
+ }
+
+ @Test(expected = SecurityException.class)
+ public void rebootRecoveryWithCommand_noPerm() {
+ doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ mRecoverySystemService.rebootRecoveryWithCommand("foo");
+ }
+
+ @Test
+ public void uncrypt_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0, 5, 25, 50, 90, 99, 100);
+
+ IRecoverySystemProgressListener listener = mock(IRecoverySystemProgressListener.class);
+ assertThat(mRecoverySystemService.uncrypt("foo.zip", listener), is(true));
+
+ assertThat(mSystemProperties.getCtlStart(), is("uncrypt"));
+ verify(mUncryptSocket, times(7)).getPercentageUncrypted();
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
new file mode 100644
index 0000000..a986b71
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 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.recoverysystem;
+
+import android.content.Context;
+import android.os.PowerManager;
+
+import java.io.FileWriter;
+
+public class RecoverySystemServiceTestable extends RecoverySystemService {
+ private static class MockInjector extends RecoverySystemService.Injector {
+ private final FakeSystemProperties mSystemProperties;
+ private final PowerManager mPowerManager;
+ private final FileWriter mUncryptPackageFileWriter;
+ private final UncryptSocket mUncryptSocket;
+
+ MockInjector(Context context, FakeSystemProperties systemProperties,
+ PowerManager powerManager, FileWriter uncryptPackageFileWriter,
+ UncryptSocket uncryptSocket) {
+ super(context);
+ mSystemProperties = systemProperties;
+ mPowerManager = powerManager;
+ mUncryptPackageFileWriter = uncryptPackageFileWriter;
+ mUncryptSocket = uncryptSocket;
+ }
+
+ @Override
+ public PowerManager getPowerManager() {
+ return mPowerManager;
+ }
+
+ @Override
+ public String systemPropertiesGet(String key) {
+ return mSystemProperties.get(key);
+ }
+
+ @Override
+ public void systemPropertiesSet(String key, String value) {
+ mSystemProperties.set(key, value);
+ }
+
+ @Override
+ public boolean uncryptPackageFileDelete() {
+ return true;
+ }
+
+ @Override
+ public String getUncryptPackageFileName() {
+ return "mock-file.txt";
+ }
+
+ @Override
+ public FileWriter getUncryptPackageFileWriter() {
+ return mUncryptPackageFileWriter;
+ }
+
+ @Override
+ public UncryptSocket connectService() {
+ return mUncryptSocket;
+ }
+
+ @Override
+ public void threadSleep(long millis) {
+ }
+ }
+
+ RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
+ PowerManager powerManager, FileWriter uncryptPackageFileWriter,
+ UncryptSocket uncryptSocket) {
+ super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
+ uncryptSocket));
+ }
+
+ public static class FakeSystemProperties {
+ private String mCtlStart = null;
+
+ public String get(String key) {
+ if (RecoverySystemService.INIT_SERVICE_UNCRYPT.equals(key)
+ || RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key)
+ || RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) {
+ return null;
+ } else {
+ throw new IllegalArgumentException("unexpected test key: " + key);
+ }
+ }
+
+ public void set(String key, String value) {
+ if ("ctl.start".equals(key)) {
+ mCtlStart = value;
+ } else {
+ throw new IllegalArgumentException("unexpected test key: " + key);
+ }
+ }
+
+ public String getCtlStart() {
+ return mCtlStart;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 7986055..8cb5197 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -58,8 +59,8 @@
// All users are unlocked so we should snapshot data for them.
doReturn(true).when(helper).isUserCredentialLocked(eq(10));
doReturn(true).when(helper).isUserCredentialLocked(eq(11));
- PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
- helper.snapshotAppData(5, info);
+ PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
+ helper.snapshotAppData(5, info, new int[]{10, 11});
assertEquals(2, info.getPendingBackups().size());
assertEquals(10, info.getPendingBackups().get(0));
@@ -79,8 +80,8 @@
doReturn(true).when(helper).isUserCredentialLocked(eq(11));
when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(239L);
- PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
- helper.snapshotAppData(7, info2);
+ PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar");
+ helper.snapshotAppData(7, info2, new int[]{10, 11});
assertEquals(1, info2.getPendingBackups().size());
assertEquals(11, info2.getPendingBackups().get(0));
@@ -234,22 +235,22 @@
wasRecentlyRestored.getPendingRestores().add(
new RestoreInfo(73 /* userId */, 239 /* appId*/, "seInfo"));
- RollbackData dataWithPendingBackup = new RollbackData(101, new File("/does/not/exist"), -1);
+ Rollback dataWithPendingBackup = new Rollback(101, new File("/does/not/exist"), -1);
dataWithPendingBackup.info.getPackages().add(pendingBackup);
- RollbackData dataWithRecentRestore = new RollbackData(17239, new File("/does/not/exist"),
+ Rollback dataWithRecentRestore = new Rollback(17239, new File("/does/not/exist"),
-1);
dataWithRecentRestore.info.getPackages().add(wasRecentlyRestored);
- RollbackData dataForDifferentUser = new RollbackData(17239, new File("/does/not/exist"),
+ Rollback dataForDifferentUser = new Rollback(17239, new File("/does/not/exist"),
-1);
dataForDifferentUser.info.getPackages().add(ignoredInfo);
- RollbackData dataForRestore = new RollbackData(17239, new File("/does/not/exist"), -1);
+ Rollback dataForRestore = new Rollback(17239, new File("/does/not/exist"), -1);
dataForRestore.info.getPackages().add(pendingRestore);
dataForRestore.info.getPackages().add(wasRecentlyRestored);
- Set<RollbackData> changed = helper.commitPendingBackupAndRestoreForUser(37,
+ Set<Rollback> changed = helper.commitPendingBackupAndRestoreForUser(37,
Arrays.asList(dataWithPendingBackup, dataWithRecentRestore, dataForDifferentUser,
dataForRestore));
InOrder inOrder = Mockito.inOrder(installer);
@@ -264,7 +265,7 @@
assertEquals(-1, pendingBackup.getPendingBackups().indexOf(37));
assertEquals(53, pendingBackup.getCeSnapshotInodes().get(37));
- // Check that changed returns correct RollbackData.
+ // Check that changed returns correct Rollback.
assertEquals(3, changed.size());
assertTrue(changed.contains(dataWithPendingBackup));
assertTrue(changed.contains(dataWithRecentRestore));
@@ -278,4 +279,15 @@
inOrder.verifyNoMoreInteractions();
}
+
+ @Test
+ public void snapshotAddDataSavesSnapshottedUsersToInfo() {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
+
+ PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
+ helper.snapshotAppData(5, info, new int[]{10, 11});
+
+ assertArrayEquals(info.getSnapshottedUsers().toArray(), new int[]{10, 11});
+ }
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index d669e905..58abf00 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -24,6 +24,7 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.telecom.Connection.VideoProvider;
+import android.telephony.Annotation.RilRadioTechnology;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index e2f5d0bb..4c22ba9 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -35,6 +35,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.telephony.Annotation.RilRadioTechnology;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index ae92464..bebbbd0 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -97,6 +97,14 @@
*/
public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
+ /**
+ * This reason is set when a call is ended in order to place an emergency call when a
+ * {@link PhoneAccount} doesn't support holding an ongoing call to place an emergency call. This
+ * reason string should only be associated with the {@link #LOCAL} disconnect code returned from
+ * {@link #getCode()}.
+ */
+ public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
+
private int mDisconnectCode;
private CharSequence mDisconnectLabel;
private CharSequence mDisconnectDescription;
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
similarity index 100%
rename from telephony/java/com/android/internal/telephony/GsmAlphabet.java
rename to telephony/common/com/android/internal/telephony/GsmAlphabet.java
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index f79aef3..9da45da 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -195,7 +195,7 @@
* @return
*/
private static int getIncomingUserId(Context context) {
- int contextUserId = context.getUserId();
+ int contextUserId = UserHandle.myUserId();
final int callingUid = Binder.getCallingUid();
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getIncomingUserHandle caller=" + callingUid + ", myuid="
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index a884a70..72f758e 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -469,4 +469,44 @@
@Retention(RetentionPolicy.SOURCE)
public @interface DataFailureCause {
}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"PRECISE_CALL_STATE_"},
+ value = {
+ PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
+ PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ PreciseCallState.PRECISE_CALL_STATE_ACTIVE,
+ PreciseCallState.PRECISE_CALL_STATE_HOLDING,
+ PreciseCallState.PRECISE_CALL_STATE_DIALING,
+ PreciseCallState.PRECISE_CALL_STATE_ALERTING,
+ PreciseCallState. PRECISE_CALL_STATE_INCOMING,
+ PreciseCallState.PRECISE_CALL_STATE_WAITING,
+ PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED,
+ PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING})
+ public @interface PreciseCallStates {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"RIL_RADIO_TECHNOLOGY_" }, value = {
+ ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN,
+ ServiceState.RIL_RADIO_TECHNOLOGY_GPRS,
+ ServiceState.RIL_RADIO_TECHNOLOGY_EDGE,
+ ServiceState.RIL_RADIO_TECHNOLOGY_UMTS,
+ ServiceState.RIL_RADIO_TECHNOLOGY_IS95A,
+ ServiceState.RIL_RADIO_TECHNOLOGY_IS95B,
+ ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT,
+ ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0,
+ ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A,
+ ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA,
+ ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA,
+ ServiceState.RIL_RADIO_TECHNOLOGY_HSPA,
+ ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B,
+ ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD,
+ ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+ ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP,
+ ServiceState.RIL_RADIO_TECHNOLOGY_GSM,
+ ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA,
+ ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+ ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA,
+ ServiceState.RIL_RADIO_TECHNOLOGY_NR})
+ public @interface RilRadioTechnology {}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c0e03a7..a0aa892 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1745,6 +1745,15 @@
"allow_emergency_video_calls_bool";
/**
+ * Flag indicating whether or not an ongoing call will be held when an outgoing emergency call
+ * is placed. If true, ongoing calls will be put on hold when an emergency call is placed. If
+ * false, placing an emergency call will trigger the disconnect of all ongoing calls before
+ * the emergency call is placed.
+ */
+ public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL =
+ "allow_hold_call_during_emergency_bool";
+
+ /**
* Flag indicating whether the carrier supports RCS presence indication for
* User Capability Exchange (UCE). When presence is supported, the device should use the
* {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the
@@ -3501,6 +3510,7 @@
sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
sDefaults.putInt(KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT, 0);
+ sDefaults.putBoolean(KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL, true);
sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
sDefaults.putBoolean(KEY_USE_RCS_SIP_OPTIONS_BOOL, false);
sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false);
diff --git a/telephony/java/com/android/internal/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java
similarity index 94%
rename from telephony/java/com/android/internal/telephony/CbGeoUtils.java
rename to telephony/java/android/telephony/CbGeoUtils.java
index 0b73252..f4ce6e7 100644
--- a/telephony/java/com/android/internal/telephony/CbGeoUtils.java
+++ b/telephony/java/android/telephony/CbGeoUtils.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.telephony;
import android.annotation.NonNull;
-import android.telephony.Rlog;
+import android.annotation.SystemApi;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -30,8 +30,17 @@
* The coordinates used by this utils class are latitude and longitude, but some algorithms in this
* class only use them as coordinates on plane, so the calculation will be inaccurate. So don't use
* this class for anything other then geo-targeting of cellbroadcast messages.
+ * @hide
*/
+@SystemApi
public class CbGeoUtils {
+
+ /**
+ * This class is never instantiated
+ * @hide
+ */
+ private CbGeoUtils() {}
+
/** Geometric interface. */
public interface Geometry {
/**
@@ -39,27 +48,36 @@
* @param p point in latitude, longitude format.
* @return {@code True} if the given point is inside the geometry.
*/
- boolean contains(LatLng p);
+ boolean contains(@NonNull LatLng p);
}
/**
* Tolerance for determining if the value is 0. If the absolute value of a value is less than
* this tolerance, it will be treated as 0.
+ * @hide
*/
public static final double EPS = 1e-7;
- /** The radius of earth. */
+ /**
+ * The radius of earth.
+ * @hide
+ */
public static final int EARTH_RADIUS_METER = 6371 * 1000;
private static final String TAG = "CbGeoUtils";
- /** The TLV tags of WAC, defined in ATIS-0700041 5.2.3 WAC tag coding. */
+ // The TLV tags of WAC, defined in ATIS-0700041 5.2.3 WAC tag coding.
+ /** @hide */
public static final int GEO_FENCING_MAXIMUM_WAIT_TIME = 0x01;
+ /** @hide */
public static final int GEOMETRY_TYPE_POLYGON = 0x02;
+ /** @hide */
public static final int GEOMETRY_TYPE_CIRCLE = 0x03;
- /** The identifier of geometry in the encoded string. */
+ // The identifier of geometry in the encoded string.
+ /** @hide */
private static final String CIRCLE_SYMBOL = "circle";
+ /** @hide */
private static final String POLYGON_SYMBOL = "polygon";
/** Point represent by (latitude, longitude). */
@@ -81,7 +99,8 @@
* @param p the point use to calculate the subtraction result.
* @return the result of this point subtract the given point {@code p}.
*/
- public LatLng subtract(LatLng p) {
+ @NonNull
+ public LatLng subtract(@NonNull LatLng p) {
return new LatLng(lat - p.lat, lng - p.lng);
}
@@ -90,7 +109,7 @@
* @param p the point use to calculate the distance.
* @return the distance in meter.
*/
- public double distance(LatLng p) {
+ public double distance(@NonNull LatLng p) {
double dlat = Math.sin(0.5 * Math.toRadians(lat - p.lat));
double dlng = Math.sin(0.5 * Math.toRadians(lng - p.lng));
double x = dlat * dlat
@@ -106,6 +125,7 @@
/**
* The class represents a simple polygon with at least 3 points.
+ * @hide
*/
public static class Polygon implements Geometry {
/**
@@ -239,7 +259,10 @@
}
}
- /** The class represents a circle. */
+ /**
+ * The class represents a circle.
+ * @hide
+ */
public static class Circle implements Geometry {
private final LatLng mCenter;
private final double mRadiusMeter;
@@ -266,6 +289,7 @@
/**
* Parse the geometries from the encoded string {@code str}. The string must follow the
* geometry encoding specified by {@link android.provider.Telephony.CellBroadcasts#GEOMETRIES}.
+ * @hide
*/
@NonNull
public static List<Geometry> parseGeometriesFromString(@NonNull String str) {
@@ -297,6 +321,7 @@
*
* @param geometries the list of geometry objects need to be encoded.
* @return the encoded string.
+ * @hide
*/
@NonNull
public static String encodeGeometriesToString(List<Geometry> geometries) {
@@ -313,6 +338,7 @@
* {@link android.provider.Telephony.CellBroadcasts#GEOMETRIES}.
* @param geometry the geometry object need to be encoded.
* @return the encoded string.
+ * @hide
*/
@NonNull
private static String encodeGeometryToString(@NonNull Geometry geometry) {
@@ -351,6 +377,7 @@
*
* @param str encoded lat/lng string.
* @Return {@link LatLng} object.
+ * @hide
*/
@NonNull
public static LatLng parseLatLngFromString(@NonNull String str) {
@@ -361,6 +388,7 @@
/**
* @Return the sign of the given value {@code value} with the specified tolerance. Return 1
* means the sign is positive, -1 means negative, 0 means the value will be treated as 0.
+ * @hide
*/
public static int sign(double value) {
if (value > EPS) return 1;
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 6df60ba..edc838c 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -62,6 +62,12 @@
}
/** @hide */
+ public CellIdentityNr(android.hardware.radio.V1_4.CellIdentityNr cid) {
+ this(cid.pci, cid.tac, cid.nrarfcn, cid.mcc, cid.mnc, cid.nci, cid.operatorNames.alphaLong,
+ cid.operatorNames.alphaShort);
+ }
+
+ /** @hide */
public CellIdentityNr sanitizeLocationInfo() {
return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 18687d4..ae45307 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -374,6 +374,7 @@
case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp);
case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp);
case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp);
+ case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp);
default: return null;
}
}
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index cea8323..8b41b8b 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -45,6 +45,14 @@
mCellSignalStrength = other.mCellSignalStrength;
}
+ /** @hide */
+ public CellInfoNr(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
+ super(ci, timeStamp);
+ final android.hardware.radio.V1_4.CellInfoNr cil = ci.info.nr();
+ mCellIdentity = new CellIdentityNr(cil.cellidentity);
+ mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrength);
+ }
+
/**
* @return a {@link CellIdentityNr} instance.
*/
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 85110c2..04ec4b6 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -354,6 +354,12 @@
*/
public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79;
+ /**
+ * Indicates that an emergency call was placed, which caused the existing connection to be
+ * hung up.
+ */
+ public static final int OUTGOING_EMERGENCY_CALL_PLACED = 80;
+
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -528,6 +534,8 @@
return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
+ case OUTGOING_EMERGENCY_CALL_PLACED:
+ return "OUTGOING_EMERGENCY_CALL_PLACED";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index ef2f121..75a79d6 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -15,9 +15,11 @@
*/
package android.telephony;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Date;
import android.util.Log;
import java.security.KeyFactory;
@@ -25,18 +27,18 @@
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
/**
* Class to represent information sent by the carrier, which will be used to encrypt
* the IMSI + IMPI. The ecryption is being done by WLAN, and the modem.
- *
* @hide
*/
+@SystemApi
public final class ImsiEncryptionInfo implements Parcelable {
private static final String LOG_TAG = "ImsiEncryptionInfo";
-
private final String mcc;
private final String mnc;
private final PublicKey publicKey;
@@ -45,11 +47,13 @@
//Date-Time in UTC when the key will expire.
private final Date expirationTime;
+ /** @hide */
public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
byte[] key, Date expirationTime) {
this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime);
}
+ /** @hide */
public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
PublicKey publicKey, Date expirationTime) {
// todo need to validate that ImsiEncryptionInfo is being created with the correct params.
@@ -63,6 +67,7 @@
this.expirationTime = expirationTime;
}
+ /** @hide */
public ImsiEncryptionInfo(Parcel in) {
int length = in.readInt();
byte b[] = new byte[length];
@@ -75,26 +80,40 @@
expirationTime = new Date(in.readLong());
}
+ /** @hide */
public String getMnc() {
return this.mnc;
}
+ /** @hide */
public String getMcc() {
return this.mcc;
}
+ /**
+ * Returns key identifier, a string that helps the authentication server to locate the
+ * private key to decrypt the permanent identity, or {@code null} when uavailable.
+ */
+ @Nullable
public String getKeyIdentifier() {
return this.keyIdentifier;
}
+ /** @hide */
public int getKeyType() {
return this.keyType;
}
+ /**
+ * Returns the carrier public key that is used for the IMSI encryption,
+ * or {@code null} when uavailable.
+ */
+ @Nullable
public PublicKey getPublicKey() {
return this.publicKey;
}
+ /** @hide */
public Date getExpirationTime() {
return this.expirationTime;
}
@@ -115,7 +134,7 @@
return 0;
}
- public static final @android.annotation.NonNull Parcelable.Creator<ImsiEncryptionInfo> CREATOR =
+ public static final @NonNull Parcelable.Creator<ImsiEncryptionInfo> CREATOR =
new Parcelable.Creator<ImsiEncryptionInfo>() {
@Override
public ImsiEncryptionInfo createFromParcel(Parcel in) {
@@ -129,7 +148,7 @@
};
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
byte[] b = publicKey.getEncoded();
dest.writeInt(b.length);
dest.writeByteArray(b);
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index f929649..9f75332 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -23,6 +23,7 @@
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.Annotation.PreciseCallStates;
import android.telephony.DisconnectCause;
import android.telephony.PreciseDisconnectCause;
@@ -48,22 +49,6 @@
@SystemApi
public final class PreciseCallState implements Parcelable {
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"PRECISE_CALL_STATE_"},
- value = {
- PRECISE_CALL_STATE_NOT_VALID,
- PRECISE_CALL_STATE_IDLE,
- PRECISE_CALL_STATE_ACTIVE,
- PRECISE_CALL_STATE_HOLDING,
- PRECISE_CALL_STATE_DIALING,
- PRECISE_CALL_STATE_ALERTING,
- PRECISE_CALL_STATE_INCOMING,
- PRECISE_CALL_STATE_WAITING,
- PRECISE_CALL_STATE_DISCONNECTED,
- PRECISE_CALL_STATE_DISCONNECTING})
- public @interface State {}
-
/** Call state is not valid (Not received a call state). */
public static final int PRECISE_CALL_STATE_NOT_VALID = -1;
/** Call state: No activity. */
@@ -85,9 +70,9 @@
/** Call state: Disconnecting. */
public static final int PRECISE_CALL_STATE_DISCONNECTING = 8;
- private @State int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
- private @State int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
- private @State int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+ private @PreciseCallStates int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
+ private @PreciseCallStates int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+ private @PreciseCallStates int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
private int mDisconnectCause = DisconnectCause.NOT_VALID;
private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
@@ -97,8 +82,9 @@
* @hide
*/
@UnsupportedAppUsage
- public PreciseCallState(@State int ringingCall, @State int foregroundCall,
- @State int backgroundCall, int disconnectCause,
+ public PreciseCallState(@PreciseCallStates int ringingCall,
+ @PreciseCallStates int foregroundCall,
+ @PreciseCallStates int backgroundCall, int disconnectCause,
int preciseDisconnectCause) {
mRingingCallState = ringingCall;
mForegroundCallState = foregroundCall;
@@ -131,21 +117,21 @@
/**
* Returns the precise ringing call state.
*/
- public @State int getRingingCallState() {
+ public @PreciseCallStates int getRingingCallState() {
return mRingingCallState;
}
/**
* Returns the precise foreground call state.
*/
- public @State int getForegroundCallState() {
+ public @PreciseCallStates int getForegroundCallState() {
return mForegroundCallState;
}
/**
* Returns the precise background call state.
*/
- public @State int getBackgroundCallState() {
+ public @PreciseCallStates int getBackgroundCallState() {
return mBackgroundCallState;
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 3fd8990..1e601cf 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -30,6 +30,7 @@
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.RilRadioTechnology;
import android.telephony.NetworkRegistrationInfo.Domain;
import android.telephony.NetworkRegistrationInfo.NRState;
import android.text.TextUtils;
@@ -155,32 +156,6 @@
*/
public static final int DUPLEX_MODE_TDD = 2;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "RIL_RADIO_TECHNOLOGY_" },
- value = {
- RIL_RADIO_TECHNOLOGY_UNKNOWN,
- RIL_RADIO_TECHNOLOGY_GPRS,
- RIL_RADIO_TECHNOLOGY_EDGE,
- RIL_RADIO_TECHNOLOGY_UMTS,
- RIL_RADIO_TECHNOLOGY_IS95A,
- RIL_RADIO_TECHNOLOGY_IS95B,
- RIL_RADIO_TECHNOLOGY_1xRTT,
- RIL_RADIO_TECHNOLOGY_EVDO_0,
- RIL_RADIO_TECHNOLOGY_EVDO_A,
- RIL_RADIO_TECHNOLOGY_HSDPA,
- RIL_RADIO_TECHNOLOGY_HSUPA,
- RIL_RADIO_TECHNOLOGY_HSPA,
- RIL_RADIO_TECHNOLOGY_EVDO_B,
- RIL_RADIO_TECHNOLOGY_EHRPD,
- RIL_RADIO_TECHNOLOGY_LTE,
- RIL_RADIO_TECHNOLOGY_HSPAP,
- RIL_RADIO_TECHNOLOGY_GSM,
- RIL_RADIO_TECHNOLOGY_TD_SCDMA,
- RIL_RADIO_TECHNOLOGY_IWLAN,
- RIL_RADIO_TECHNOLOGY_LTE_CA,
- RIL_RADIO_TECHNOLOGY_NR})
- public @interface RilRadioTechnology {}
/**
* Available radio technologies for GSM, UMTS and CDMA.
* Duplicates the constants from hardware/radio/include/ril.h
diff --git a/telephony/java/android/telephony/SmsCbLocation.java b/telephony/java/android/telephony/SmsCbLocation.java
index adf7154..663e8e2 100644
--- a/telephony/java/android/telephony/SmsCbLocation.java
+++ b/telephony/java/android/telephony/SmsCbLocation.java
@@ -65,9 +65,12 @@
/**
* Construct a location object for the PLMN, LAC, and Cell ID. This class is immutable, so
* the same object can be reused for multiple broadcasts.
- * @hide
+ *
+ * @param plmn the MCC/MNC of the network
+ * @param lac the GSM location area code, or UMTS service area code
+ * @param cid the GSM or UMTS cell ID
*/
- public SmsCbLocation(String plmn, int lac, int cid) {
+ public SmsCbLocation(@NonNull String plmn, int lac, int cid) {
mPlmn = plmn;
mLac = lac;
mCid = cid;
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index dc991b9..737ead1 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -25,9 +25,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Telephony.CellBroadcasts;
-
-import com.android.internal.telephony.CbGeoUtils;
-import com.android.internal.telephony.CbGeoUtils.Geometry;
+import android.telephony.CbGeoUtils.Geometry;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -140,8 +138,8 @@
public @interface MessagePriority {}
/**
- * ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
- * @hide
+ * Integer indicating that the maximum wait time is not set.
+ * Based on ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
*/
public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255;
@@ -211,6 +209,7 @@
/**
* Create a new SmsCbMessage with the specified data.
+ * @hide
*/
public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
@NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
@@ -223,14 +222,14 @@
}
/**
- * Create a new {@link SmsCbMessage} with the warning area coordinates information.
- * @hide
+ * Create a new {@link SmsCbMessage} with the specified data, including warning area
+ * coordinates information.
*/
public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
- SmsCbLocation location, int serviceCategory, String language, String body,
- int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo,
- int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis,
- int slotIndex) {
+ @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
+ @Nullable String body, int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo,
+ @Nullable SmsCbCmasInfo cmasWarningInfo, int maximumWaitTimeSec,
+ @Nullable List<Geometry> geometries, long receivedTimeMillis, int slotIndex) {
mMessageFormat = messageFormat;
mGeographicalScope = geographicalScope;
mSerialNumber = serialNumber;
@@ -414,9 +413,8 @@
/**
* Get the Geo-Fencing Maximum Wait Time.
* @return the time in second.
- * @hide
*/
- public int getMaximumWaitingTime() {
+ public int getMaximumWaitingDuration() {
return mMaximumWaitTimeSec;
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 9d1b7a9..3c890a1 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -61,6 +61,7 @@
import android.telephony.ims.ImsMmTelManager;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.telephony.ISetOpportunisticDataCallback;
import com.android.internal.telephony.ISub;
@@ -76,6 +77,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -910,6 +912,11 @@
private final Context mContext;
private volatile INetworkPolicyManager mNetworkPolicy;
+ // Cache of Resource that has been created in getResourcesForSubId. Key is a Pair containing
+ // the Context and subId.
+ private static final Map<Pair<Context, Integer>, Resources> sResourcesCache =
+ new ConcurrentHashMap<>();
+
/**
* A listener class for monitoring changes to {@link SubscriptionInfo} records.
* <p>
@@ -2304,8 +2311,20 @@
* @return Resources associated with Subscription.
* @hide
*/
+ @NonNull
public static Resources getResourcesForSubId(Context context, int subId,
boolean useRootLocale) {
+ // Check if resources for this context and subId already exist in the resource cache.
+ // Resources that use the root locale are not cached.
+ Pair<Context, Integer> cacheKey = null;
+ if (isValidSubscriptionId(subId) && !useRootLocale) {
+ cacheKey = Pair.create(context, subId);
+ if (sResourcesCache.containsKey(cacheKey)) {
+ // Cache hit. Use cached Resources.
+ return sResourcesCache.get(cacheKey);
+ }
+ }
+
final SubscriptionInfo subInfo =
SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
@@ -2325,7 +2344,13 @@
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
DisplayMetrics newMetrics = new DisplayMetrics();
newMetrics.setTo(metrics);
- return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
+ Resources res = new Resources(context.getResources().getAssets(), newMetrics, newConfig);
+
+ if (cacheKey != null) {
+ // Save the newly created Resources in the resource cache.
+ sResourcesCache.put(cacheKey, res);
+ }
+ return res;
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 55212cd..e99465d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -200,12 +200,29 @@
/** @hide */
static public final int OTASP_SIM_UNPROVISIONED = 5;
- /** @hide */
+ /**
+ * Used in carrier Wi-Fi for IMSI + IMPI encryption, this indicates a public key that's
+ * available for use in ePDG links.
+ *
+ * @hide
+ */
+ @SystemApi
static public final int KEY_TYPE_EPDG = 1;
- /** @hide */
+ /**
+ * Used in carrier Wi-Fi for IMSI + IMPI encryption, this indicates a public key that's
+ * available for use in WLAN links.
+ *
+ * @hide
+ */
+ @SystemApi
static public final int KEY_TYPE_WLAN = 2;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"KEY_TYPE_"}, value = {KEY_TYPE_EPDG, KEY_TYPE_WLAN})
+ public @interface KeyType {}
+
/**
* No Single Radio Voice Call Continuity (SRVCC) handover is active.
* See TS 23.216 for more information.
@@ -3814,25 +3831,27 @@
}
/**
- * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
- * This includes the public key and the key identifier. For multi-sim devices, if no subId
- * has been specified, we will return the value for the dafault data sim.
- * Return null if it is unavailable.
+ * Returns carrier specific information that will be used to encrypt the IMSI and IMPI,
+ * including the public key and the key identifier; or {@code null} if not available.
* <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * @param keyType whether the key is being used for wlan or epdg. Valid key types are
- * {@link TelephonyManager#KEY_TYPE_EPDG} or
- * {@link TelephonyManager#KEY_TYPE_WLAN}.
+ * For a multi-sim device, the dafault data sim is used if not specified.
+ * <p>
+ * Requires Permission: READ_PRIVILEGED_PHONE_STATE.
+ *
+ * @param keyType whether the key is being used for EPDG or WLAN. Valid values are
+ * {@link #KEY_TYPE_EPDG} or {@link #KEY_TYPE_WLAN}.
* @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
* IMSI and IMPI. This includes the public key and the key identifier. This information
- * will be stored in the device keystore. The system will return a null when no key was
- * found, and the carrier does not require a key. The system will throw
- * IllegalArgumentException when an invalid key is sent or when key is required but
+ * will be stored in the device keystore. {@code null} will be returned when no key is
+ * found, and the carrier does not require a key.
+ * @throws IllegalArgumentException when an invalid key is found or when key is required but
* not found.
* @hide
*/
- public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi
+ @Nullable
+ public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) {
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null) {
@@ -3860,14 +3879,21 @@
}
/**
- * Resets the Carrier Keys in the database. This involves 2 steps:
+ * Resets the carrier keys used to encrypt the IMSI and IMPI.
+ * <p>
+ * This involves 2 steps:
* 1. Delete the keys from the database.
* 2. Send an intent to download new Certificates.
* <p>
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * For a multi-sim device, the dafault data sim is used if not specified.
+ * <p>
+ * Requires Permission: MODIFY_PHONE_STATE.
+ *
+ * @see #getCarrierInfoForImsiEncryption
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @SystemApi
public void resetCarrierKeysForImsiEncryption() {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -3894,7 +3920,7 @@
* @return true if the digit at position keyType is 1, else false.
* @hide
*/
- private static boolean isKeyEnabled(int keyAvailability, int keyType) {
+ private static boolean isKeyEnabled(int keyAvailability, @KeyType int keyType) {
int returnValue = (keyAvailability >> (keyType - 1)) & 1;
return (returnValue == 1) ? true : false;
}
@@ -3903,7 +3929,7 @@
* If Carrier requires Imsi to be encrypted.
* @hide
*/
- private boolean isImsiEncryptionRequired(int subId, int keyType) {
+ private boolean isImsiEncryptionRequired(int subId, @KeyType int keyType) {
CarrierConfigManager configManager =
(CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (configManager == null) {
@@ -7673,8 +7699,8 @@
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@SystemApi
- public boolean isTetherApnRequired() {
- return isTetherApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
+ public boolean isTetheringApnRequired() {
+ return isTetheringApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
}
/**
@@ -7684,11 +7710,11 @@
* @return {@code true} if DUN APN is required for tethering.
* @hide
*/
- public boolean isTetherApnRequired(int subId) {
+ public boolean isTetheringApnRequired(int subId) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.isTetherApnRequiredForSubscriber(subId);
+ return telephony.isTetheringApnRequiredForSubscriber(subId);
} catch (RemoteException ex) {
Rlog.e(TAG, "hasMatchedTetherApnSetting RemoteException", ex);
} catch (NullPointerException ex) {
@@ -8806,7 +8832,10 @@
@Deprecated
public boolean isTtyModeSupported() {
try {
- TelecomManager telecomManager = TelecomManager.from(mContext);
+ TelecomManager telecomManager = null;
+ if (mContext != null) {
+ telecomManager = mContext.getSystemService(TelecomManager.class);
+ }
if (telecomManager != null) {
return telecomManager.isTtySupported();
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index eb0e2f7..5fd0af5 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -979,25 +979,25 @@
/**
* Get the status of the MmTel Feature registered on this subscription.
+ * @param executor The executor that will be used to call the callback.
* @param callback A callback containing an Integer describing the current state of the
* MmTel feature, Which will be one of the following:
* {@link ImsFeature#STATE_UNAVAILABLE},
* {@link ImsFeature#STATE_INITIALIZING},
* {@link ImsFeature#STATE_READY}. Will be called using the executor
* specified when the service state has been retrieved from the IMS service.
- * @param executor The executor that will be used to call the callback.
* @throws ImsException if the IMS service associated with this subscription is not available or
* the IMS service is not available.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void getFeatureState(@NonNull @ImsFeature.ImsState Consumer<Integer> callback,
- @NonNull @CallbackExecutor Executor executor) throws ImsException {
- if (callback == null) {
- throw new IllegalArgumentException("Must include a non-null Consumer.");
- }
+ public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
+ @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+ if (callback == null) {
+ throw new IllegalArgumentException("Must include a non-null Consumer.");
+ }
try {
getITelephony().getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
@Override
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 119f890..e96d082 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -199,12 +199,19 @@
/** @hide*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
+ CAPABILITY_TYPE_NONE,
CAPABILITY_TYPE_OPTIONS_UCE,
CAPABILITY_TYPE_PRESENCE_UCE
})
public @interface RcsImsCapabilityFlag {}
/**
+ * Undefined capability type for initialization
+ * @hide
+ */
+ public static final int CAPABILITY_TYPE_NONE = 0;
+
+ /**
* This carrier supports User Capability Exchange using SIP OPTIONS as defined by the
* framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS.
* If not set, this RcsFeature should not service capability requests.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index b502ee7..2f18049e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -819,7 +819,7 @@
* @return {@code true} if DUN APN is required for tethering.
* @hide
*/
- boolean isTetherApnRequiredForSubscriber(int subId);
+ boolean isTetheringApnRequiredForSubscriber(int subId);
/**
* Enables framework IMS and triggers IMS Registration.
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index d29ef35..d36d95b 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -20,7 +20,6 @@
import android.os.Build;
import android.provider.Telephony;
import android.telephony.SmsMessage;
-import android.text.Emoji;
import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
@@ -404,9 +403,9 @@
if (!breakIterator.isBoundary(nextPos)) {
int breakPos = breakIterator.preceding(nextPos);
while (breakPos + 4 <= nextPos
- && Emoji.isRegionalIndicatorSymbol(
+ && isRegionalIndicatorSymbol(
Character.codePointAt(msgBody, breakPos))
- && Emoji.isRegionalIndicatorSymbol(
+ && isRegionalIndicatorSymbol(
Character.codePointAt(msgBody, breakPos + 2))) {
// skip forward over flags (pairs of Regional Indicator Symbol)
breakPos += 4;
@@ -422,6 +421,11 @@
return nextPos;
}
+ private static boolean isRegionalIndicatorSymbol(int codePoint) {
+ /** Based on http://unicode.org/Public/emoji/3.0/emoji-sequences.txt */
+ return 0x1F1E6 <= codePoint && codePoint <= 0x1F1FF;
+ }
+
/**
* Calculate the TextEncodingDetails of a message encoded in Unicode.
*/
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index c3d490a..5766287 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -25,17 +25,17 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
+import android.telephony.CbGeoUtils;
+import android.telephony.CbGeoUtils.Circle;
+import android.telephony.CbGeoUtils.Geometry;
+import android.telephony.CbGeoUtils.LatLng;
+import android.telephony.CbGeoUtils.Polygon;
import android.telephony.SmsCbLocation;
import android.telephony.SmsCbMessage;
import android.util.Pair;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.telephony.CbGeoUtils;
-import com.android.internal.telephony.CbGeoUtils.Circle;
-import com.android.internal.telephony.CbGeoUtils.Geometry;
-import com.android.internal.telephony.CbGeoUtils.LatLng;
-import com.android.internal.telephony.CbGeoUtils.Polygon;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsConstants;
import com.android.internal.telephony.gsm.GsmSmsCbMessage.GeoFencingTriggerMessage.CellBroadcastIdentity;
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 727684e..1de6260 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -765,6 +765,12 @@
/** {@hide} */
@Override
+ public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@hide} */
+ @Override
public int getUserId() {
throw new UnsupportedOperationException();
}
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
new file mode 100644
index 0000000..5e9ef8e
--- /dev/null
+++ b/tests/PlatformCompatGating/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2019 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.
+//
+
+android_test {
+ name: "PlatformCompatGating",
+ // Only compile source java files in this apk.
+ srcs: ["src/**/*.java"],
+ certificate: "platform",
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: [
+ "junit",
+ "android-support-test",
+ "mockito-target-minus-junit4",
+ "truth-prebuilt",
+ "platform-compat-test-rules"
+ ],
+}
diff --git a/tests/PlatformCompatGating/AndroidManifest.xml b/tests/PlatformCompatGating/AndroidManifest.xml
new file mode 100644
index 0000000..7f14b83
--- /dev/null
+++ b/tests/PlatformCompatGating/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.gating">
+ <application android:label="GatingTest">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.tests.gating"/>
+</manifest>
diff --git a/tests/PlatformCompatGating/AndroidTest.xml b/tests/PlatformCompatGating/AndroidTest.xml
new file mode 100644
index 0000000..c626848
--- /dev/null
+++ b/tests/PlatformCompatGating/AndroidTest.xml
@@ -0,0 +1,30 @@
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Test compatibility change gating.">
+ <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="PlatformCompatGating.apk"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="Gating"/>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.tests.gating"/>
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java
new file mode 100644
index 0000000..731be8e
--- /dev/null
+++ b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 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.compat.testing;
+
+import android.compat.Compatibility;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * This is a dummy API to test gating
+ *
+ * @hide
+ */
+public class DummyApi {
+
+ public static final long CHANGE_ID = 666013;
+ public static final long CHANGE_ID_1 = 666014;
+ public static final long CHANGE_ID_2 = 666015;
+ public static final long CHANGE_SYSTEM_SERVER = 666016;
+
+ /**
+ * Dummy method
+ * @return "A" if change is enabled, "B" otherwise.
+ */
+ public static String dummyFunc() {
+ if (Compatibility.isChangeEnabled(CHANGE_ID)) {
+ return "A";
+ }
+ return "B";
+ }
+
+ /**
+ * Dummy combined method
+ * @return "0" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is disabled,
+ "1" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is enabled,
+ "2" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is disabled,
+ "3" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is enabled.
+ */
+ public static String dummyCombinedFunc() {
+ if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+ && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+ return "0";
+ } else if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+ && Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+ return "1";
+ } else if (Compatibility.isChangeEnabled(CHANGE_ID_1)
+ && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+ return "2";
+ }
+ return "3";
+ }
+
+ /**
+ * Dummy api using system server API.
+ */
+ public static boolean dummySystemServer(Context context) {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub
+ .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ if (platformCompat == null) {
+ throw new RuntimeException("Could not obtain IPlatformCompat instance!");
+ }
+ String packageName = context.getPackageName();
+ try {
+ return platformCompat.isChangeEnabledByPackageName(CHANGE_SYSTEM_SERVER, packageName,
+ context.getUserId());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Could not get change value!", e);
+ }
+ }
+}
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java
new file mode 100644
index 0000000..dc317f19
--- /dev/null
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 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.tests.gating;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.compat.testing.PlatformCompatChangeRule;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.compat.testing.DummyApi;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for platform compatibility change gating.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PlatformCompatGatingTest {
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Test
+ @EnableCompatChanges({DummyApi.CHANGE_ID})
+ public void testDummyGatingPositive() {
+ assertThat(DummyApi.dummyFunc()).isEqualTo("A");
+ }
+
+ @Test
+ @DisableCompatChanges({DummyApi.CHANGE_ID})
+ public void testDummyGatingNegative() {
+ assertThat(DummyApi.dummyFunc()).isEqualTo("B");
+ }
+
+ @Test
+ @DisableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+ public void testDummyGatingCombined0() {
+ assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("0");
+ }
+
+ @Test
+ @DisableCompatChanges({DummyApi.CHANGE_ID_1})
+ @EnableCompatChanges({DummyApi.CHANGE_ID_2})
+ public void testDummyGatingCombined1() {
+ assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("1");
+ }
+
+ @Test
+ @EnableCompatChanges({DummyApi.CHANGE_ID_1})
+ @DisableCompatChanges({DummyApi.CHANGE_ID_2})
+ public void testDummyGatingCombined2() {
+ assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("2");
+ }
+
+ @Test
+ @EnableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+ public void testDummyGatingCombined3() {
+ assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("3");
+ }
+
+ @Test
+ @EnableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
+ public void testDummyGatingPositiveSystemServer() {
+ assertThat(
+ DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isTrue();
+ }
+
+ @Test
+ @DisableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
+ public void testDummyGatingNegativeSystemServer() {
+ assertThat(
+ DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isFalse();
+ }
+}
diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp
new file mode 100644
index 0000000..8211ef5
--- /dev/null
+++ b/tests/PlatformCompatGating/test-rules/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 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.
+//
+
+java_library {
+ name: "platform-compat-test-rules",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "junit",
+ "android-support-test",
+ "truth-prebuilt",
+ "core-compat-test-rules"
+ ],
+}
\ No newline at end of file
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
new file mode 100644
index 0000000..932ec64
--- /dev/null
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2019 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.compat.testing;
+
+import android.app.Instrumentation;
+import android.compat.Compatibility;
+import android.compat.Compatibility.ChangeConfig;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+import com.android.internal.compat.IPlatformCompat;
+
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
+import org.junit.runners.model.Statement;
+
+/**
+ * Allows tests to specify the which change to disable.
+ *
+ * <p>To use add the following to the test class. It will only change the behavior of a test method
+ * if it is annotated with
+ * {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or
+ * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges}.
+ * </p>
+ * <pre>
+ * @Rule
+ * public TestRule compatChangeRule = new PlatformCompatChangeRule();
+ * </pre>
+ *
+ * <p>Each test method that needs to disable a specific change needs to be annotated
+ * with {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or
+ * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges} specifying the change
+ * id. e.g.:
+ * </p>
+ * <pre>
+ * @Test
+ * @DisableCompatChanges({42})
+ * public void testAsIfChange42Disabled() {
+ * // check behavior
+ * }
+ *
+ * @Test
+ * @EnableCompatChanges({42})
+ * public void testAsIfChange42Enabled() {
+ * // check behavior
+ *
+ * </pre>
+ */
+public class PlatformCompatChangeRule extends CoreCompatChangeRule {
+
+ @Override
+ protected Statement createStatementForConfig(final Statement statement, ChangeConfig config) {
+ return new CompatChangeStatement(statement, config);
+ }
+
+
+ private static class CompatChangeStatement extends Statement {
+ private final Statement mTestStatement;
+ private final ChangeConfig mConfig;
+
+ private CompatChangeStatement(Statement testStatement, ChangeConfig config) {
+ this.mTestStatement = testStatement;
+ this.mConfig = config;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ String packageName = instrumentation.getTargetContext().getPackageName();
+ IPlatformCompat platformCompat = IPlatformCompat.Stub
+ .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ if (platformCompat == null) {
+ throw new IllegalStateException("Could not get IPlatformCompat service!");
+ }
+ Compatibility.setOverrides(mConfig);
+ try {
+ platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
+ packageName);
+ try {
+ mTestStatement.evaluate();
+ } finally {
+ platformCompat.clearOverridesForTest(packageName);
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
+ } finally {
+ Compatibility.clearOverrides();
+ }
+ }
+ }
+}
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index aec4055..231d045b 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -12,88 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-android_test_helper_app {
- name: "RollbackTestAppAv1",
- manifest: "TestApp/Av1.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v1"],
-}
-
-android_test_helper_app {
- name: "RollbackTestAppAv2",
- manifest: "TestApp/Av2.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v2"],
-}
-
-android_test_helper_app {
- name: "RollbackTestAppAv3",
- manifest: "TestApp/Av3.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v3"],
-}
-
-android_test_helper_app {
- name: "RollbackTestAppACrashingV2",
- manifest: "TestApp/ACrashingV2.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v2"],
-}
-
-android_test_helper_app {
- name: "RollbackTestAppBv1",
- manifest: "TestApp/Bv1.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v1"],
-}
-
-android_test_helper_app {
- name: "RollbackTestAppBv2",
- manifest: "TestApp/Bv2.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v2"],
-}
-
-android_test_helper_app {
- name: "RollbackTestAppASplitV1",
- manifest: "TestApp/Av1.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v1"],
- package_splits: ["anydpi"],
-}
-
-android_test_helper_app {
- name: "RollbackTestAppASplitV2",
- manifest: "TestApp/Av2.xml",
- sdk_version: "current",
- srcs: ["TestApp/src/**/*.java"],
- resource_dirs: ["TestApp/res_v2"],
- package_splits: ["anydpi"],
-}
-
android_test {
name: "RollbackTest",
manifest: "RollbackTest/AndroidManifest.xml",
srcs: ["RollbackTest/src/**/*.java"],
- static_libs: ["androidx.test.rules"],
+ static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
test_suites: ["general-tests"],
- java_resources: [
- ":RollbackTestAppAv1",
- ":RollbackTestAppAv2",
- ":RollbackTestAppAv3",
- ":RollbackTestAppACrashingV2",
- ":RollbackTestAppBv1",
- ":RollbackTestAppBv2",
- ":RollbackTestAppASplitV1",
- ":RollbackTestAppASplitV2",
- ],
test_config: "RollbackTest.xml",
// TODO: sdk_version: "test_current" when Intent#resolveSystemservice is TestApi
}
@@ -105,3 +29,11 @@
test_suites: ["general-tests"],
test_config: "StagedRollbackTest.xml",
}
+
+java_test_host {
+ name: "MultiUserRollbackTest",
+ srcs: ["MultiUserRollbackTest/src/**/*.java"],
+ libs: ["tradefed"],
+ test_suites: ["general-tests"],
+ test_config: "MultiUserRollbackTest.xml",
+}
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
new file mode 100644
index 0000000..41cec46
--- /dev/null
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Runs rollback tests for multiple users">
+ <option name="test-suite-tag" value="MultiUserRollbackTest" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
+ </test>
+</configuration>
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
new file mode 100644
index 0000000..52f6eba
--- /dev/null
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 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.tests.rollback.host;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Runs rollback tests for multiple users.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class MultiUserRollbackTest extends BaseHostJUnit4Test {
+ // The user that was running originally when the test starts.
+ private int mOriginalUserId;
+ private int mSecondaryUserId = -1;
+ private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60;
+ private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000;
+
+
+ @After
+ public void tearDown() throws Exception {
+ getDevice().switchUser(mOriginalUserId);
+ getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
+ removeSecondaryUserIfNecessary();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ mOriginalUserId = getDevice().getCurrentUser();
+ installPackageAsUser("RollbackTest.apk", true, mOriginalUserId);
+ createAndSwitchToSecondaryUserIfNecessary();
+ installPackageAsUser("RollbackTest.apk", true, mSecondaryUserId);
+ }
+
+ @Test
+ public void testBasicForSecondaryUser() throws Exception {
+ runPhaseForUsers("testBasic", mSecondaryUserId);
+ }
+
+ @Test
+ public void testMultipleUsers() throws Exception {
+ runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
+ runPhaseForUsers("testMultipleUsersUpgradeToV2", mOriginalUserId);
+ runPhaseForUsers("testMultipleUsersUpdateUserData", mOriginalUserId, mSecondaryUserId);
+ switchToUser(mOriginalUserId);
+ getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A");
+ runPhaseForUsers("testMultipleUsersVerifyUserdataRollback", mOriginalUserId,
+ mSecondaryUserId);
+ }
+
+ /**
+ * Run the phase for the given user ids, in the order they are given.
+ */
+ private void runPhaseForUsers(String phase, int... userIds) throws Exception {
+ for (int userId: userIds) {
+ switchToUser(userId);
+ assertTrue(runDeviceTests("com.android.tests.rollback",
+ "com.android.tests.rollback.MultiUserRollbackTest",
+ phase));
+ }
+ }
+
+ private void removeSecondaryUserIfNecessary() throws Exception {
+ if (mSecondaryUserId != -1) {
+ getDevice().removeUser(mSecondaryUserId);
+ mSecondaryUserId = -1;
+ }
+ }
+
+ private void createAndSwitchToSecondaryUserIfNecessary() throws Exception {
+ if (mSecondaryUserId == -1) {
+ mOriginalUserId = getDevice().getCurrentUser();
+ mSecondaryUserId = getDevice().createUser("MultiUserRollbackTest_User"
+ + System.currentTimeMillis());
+ switchToUser(mSecondaryUserId);
+ }
+ }
+
+ private void switchToUser(int userId) throws Exception {
+ if (getDevice().getCurrentUser() == userId) {
+ return;
+ }
+
+ assertTrue(getDevice().switchUser(userId));
+ for (int i = 0; i < SWITCH_USER_COMPLETED_NUMBER_OF_POLLS; ++i) {
+ String userState = getDevice().executeShellCommand("am get-started-user-state "
+ + userId);
+ if (userState.contains("RUNNING_UNLOCKED")) {
+ return;
+ }
+ Thread.sleep(SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS);
+ }
+ fail("User switch to user " + userId + " timed out");
+ }
+}
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index 70cd867..a14b01c 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -22,8 +22,9 @@
<option name="package" value="com.android.tests.rollback" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <!-- Exclude the StagedRollbackTest tests, which needs to be specially
- driven from the StagedRollbackTest host test -->
+ <!-- Exclude the StagedRollbackTest and MultiUserRollbackTest tests, which need to be
+ specially driven from the StagedRollbackTest and MultiUserRollbackTest host test -->
<option name="exclude-filter" value="com.android.tests.rollback.StagedRollbackTest" />
+ <option name="exclude-filter" value="com.android.tests.rollback.MultiUserRollbackTest" />
</test>
</configuration>
diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
index 5380dc9..2b8c964 100644
--- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.android.tests.rollback" >
<application>
- <receiver android:name="com.android.tests.rollback.LocalIntentSender"
+ <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
deleted file mode 100644
index 267ef73..0000000
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.rollback;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Make IntentSender that sends intent locally.
- */
-public class LocalIntentSender extends BroadcastReceiver {
-
- private static final String TAG = "RollbackTest";
-
- private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- sIntentSenderResults.add(intent);
- }
-
- /**
- * Get a LocalIntentSender.
- */
- static IntentSender getIntentSender() {
- Context context = InstrumentationRegistry.getContext();
- Intent intent = new Intent(context, LocalIntentSender.class);
- PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
- return pending.getIntentSender();
- }
-
- /**
- * Returns the most recent Intent sent by a LocalIntentSender.
- */
- static Intent getIntentSenderResult() throws InterruptedException {
- return sIntentSenderResults.take();
- }
-}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
new file mode 100644
index 0000000..0ffe041
--- /dev/null
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 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.tests.rollback;
+
+import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
+import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.rollback.lib.Rollback;
+import com.android.cts.rollback.lib.RollbackUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+
+@RunWith(JUnit4.class)
+public class MultiUserRollbackTest {
+
+ @Before
+ public void adoptShellPermissions() {
+ InstallUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
+ Manifest.permission.MANAGE_ROLLBACKS);
+ }
+
+ @After
+ public void dropShellPermissions() {
+ InstallUtils.dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void testBasic() throws Exception {
+ new RollbackTest().testBasic();
+ }
+
+ /**
+ * Install version 1 of the test app. This method is run for both users.
+ */
+ @Test
+ public void testMultipleUsersInstallV1() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+ }
+
+ /**
+ * Upgrade the test app to version 2. This method should only run once as the system user,
+ * and will update the app for both users.
+ */
+ @Test
+ public void testMultipleUsersUpgradeToV2() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ }
+
+ /**
+ * This method is run for both users. Assert that the test app has upgraded for both users, and
+ * update their userdata to reflect this new version.
+ */
+ @Test
+ public void testMultipleUsersUpdateUserData() {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ InstallUtils.processUserData(TestApp.A);
+ }
+
+ /**
+ * The system will have rolled back the test app at this stage. Verify that the rollback has
+ * taken place, and that the userdata has been correctly rolled back. This method is run for
+ * both users.
+ */
+ @Test
+ public void testMultipleUsersVerifyUserdataRollback() {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+ }
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
deleted file mode 100644
index ebe5418..0000000
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.rollback;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A broadcast receiver that can be used to get
- * ACTION_ROLLBACK_COMMITTED broadcasts.
- */
-class RollbackBroadcastReceiver extends BroadcastReceiver {
-
- private static final String TAG = "RollbackTest";
-
- private final BlockingQueue<Intent> mRollbackBroadcasts = new LinkedBlockingQueue<>();
-
- /**
- * Creates a RollbackBroadcastReceiver and registers it with the given
- * context.
- */
- RollbackBroadcastReceiver() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED);
- InstrumentationRegistry.getContext().registerReceiver(this, filter);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(TAG, "Received rollback broadcast intent");
- mRollbackBroadcasts.add(intent);
- }
-
- /**
- * Polls for at most the given amount of time for the next rollback
- * broadcast.
- */
- Intent poll(long timeout, TimeUnit unit) throws InterruptedException {
- return mRollbackBroadcasts.poll(timeout, unit);
- }
-
- /**
- * Waits forever for the next rollback broadcast.
- */
- Intent take() throws InterruptedException {
- return mRollbackBroadcasts.take();
- }
-
- /**
- * Unregisters this broadcast receiver.
- */
- void unregister() {
- InstrumentationRegistry.getContext().unregisterReceiver(this);
- }
-}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 1b002ca..277c04f 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -16,14 +16,14 @@
package com.android.tests.rollback;
-import static com.android.tests.rollback.RollbackTestUtils.assertPackageRollbackInfoEquals;
-import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
-import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
-import static com.android.tests.rollback.RollbackTestUtils.processUserData;
+import static com.android.cts.install.lib.InstallUtils.processUserData;
+import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
+import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+import static com.android.cts.rollback.lib.RollbackUtils.waitForAvailableRollback;
+import static com.android.cts.rollback.lib.RollbackUtils.waitForUnavailableRollback;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.fail;
import android.Manifest;
@@ -31,15 +31,21 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.VersionedPackage;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+import com.android.cts.rollback.lib.Rollback;
+import com.android.cts.rollback.lib.RollbackBroadcastReceiver;
+import com.android.cts.rollback.lib.RollbackUtils;
+
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,8 +63,6 @@
private static final String TAG = "RollbackTest";
- private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
- private static final String TEST_APP_B = "com.android.tests.rollback.testapp.B";
private static final String INSTRUMENTED_APP = "com.android.tests.rollback";
// copied from PackageManagerService#PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS
@@ -88,7 +92,7 @@
context.registerReceiver(enableRollbackReceiver, enableRollbackFilter);
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -97,18 +101,18 @@
// Register a broadcast receiver for notification when the
// rollback has been committed.
RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- // Uninstall TEST_APP_A
- RollbackTestUtils.uninstall(TEST_APP_A);
- assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ // Uninstall TestApp.A
+ Uninstall.packages(TestApp.A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
// TODO: There is currently a race condition between when the app is
// uninstalled and when rollback manager deletes the rollback. Fix it
// so that's not the case!
for (int i = 0; i < 5; ++i) {
RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
if (rollback != null) {
Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
Thread.sleep(1000);
@@ -116,50 +120,55 @@
}
// The app should not be available for rollback.
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ waitForUnavailableRollback(TestApp.A);
// There should be no recently committed rollbacks for this package.
- assertNull(getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A));
+ assertThat(getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A)).isNull();
// Install v1 of the app (without rollbacks enabled).
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
// Upgrade from v1 to v2, with rollbacks enabled.
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
// The app should now be available for rollback.
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ RollbackInfo available = waitForAvailableRollback(TestApp.A);
+ assertThat(available).isNotStaged();
+ assertThat(available).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
// We should not have received any rollback requests yet.
// TODO: Possibly flaky if, by chance, some other app on device
// happens to be rolled back at the same time?
- assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+ assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
// Roll back the app.
- RollbackTestUtils.rollback(rollback.getRollbackId());
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ RollbackUtils.rollback(available.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
// Verify we received a broadcast for the rollback.
// TODO: Race condition between the timeout and when the broadcast is
// received could lead to test flakiness.
Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
- assertNotNull(broadcast);
- assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+ assertThat(broadcast).isNotNull();
+ assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
// Verify the recent rollback has been recorded.
- rollback = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ RollbackInfo committed = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(committed).isNotNull();
+ assertThat(committed).isNotStaged();
+ assertThat(committed).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(committed).hasRollbackId(available.getRollbackId());
broadcastReceiver.unregister();
context.unregisterReceiver(enableRollbackReceiver);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -169,50 +178,54 @@
@Test
public void testAvailableRollbackPersistence() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackTestUtils.uninstall(TEST_APP_B);
- RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ Uninstall.packages(TestApp.B);
+ Install.single(TestApp.B1).commit();
+ Install.single(TestApp.B2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
// Both test apps should now be available for rollback.
- RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+ RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
+ assertThat(rollbackA).isNotNull();
+ assertThat(rollbackA).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
- RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_B);
- assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+ RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
+ assertThat(rollbackB).isNotNull();
+ assertThat(rollbackB).packagesContainsExactly(
+ Rollback.from(TestApp.B2).to(TestApp.B1));
// Reload the persisted data.
rm.reloadPersistedData();
// The apps should still be available for rollback.
- rollbackA = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+ rollbackA = waitForAvailableRollback(TestApp.A);
+ assertThat(rollbackA).isNotNull();
+ assertThat(rollbackA).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
- rollbackB = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_B);
- assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+ rollbackB = waitForAvailableRollback(TestApp.B);
+ assertThat(rollbackB).isNotNull();
+ assertThat(rollbackB).packagesContainsExactly(
+ Rollback.from(TestApp.B2).to(TestApp.B1));
// Rollback of B should not rollback A
- RollbackTestUtils.rollback(rollbackB.getRollbackId());
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ RollbackUtils.rollback(rollbackB.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -222,49 +235,76 @@
@Test
public void testAvailableMultiPackageRollbackPersistence() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.uninstall(TEST_APP_B);
- RollbackTestUtils.installMultiPackage(false,
- "RollbackTestAppAv1.apk",
- "RollbackTestAppBv1.apk");
- RollbackTestUtils.installMultiPackage(true,
- "RollbackTestAppAv2.apk",
- "RollbackTestAppBv2.apk");
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ Uninstall.packages(TestApp.A, TestApp.B);
+ Install.multi(TestApp.A1, TestApp.B1).commit();
+ Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
+
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
// The app should now be available for rollback.
- RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoForAandB(rollbackA);
+ RollbackInfo availableA = waitForAvailableRollback(TestApp.A);
+ assertThat(availableA).isNotNull();
+ assertThat(availableA).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
- RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_B);
- assertRollbackInfoForAandB(rollbackB);
+ RollbackInfo availableB = waitForAvailableRollback(TestApp.B);
+ assertThat(availableB).isNotNull();
+ assertThat(availableB).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
+
+ // Assert they're both the same rollback
+ assertThat(availableA).hasRollbackId(availableB.getRollbackId());
// Reload the persisted data.
rm.reloadPersistedData();
// The apps should still be available for rollback.
- rollbackA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoForAandB(rollbackA);
+ availableA = waitForAvailableRollback(TestApp.A);
+ assertThat(availableA).isNotNull();
+ assertThat(availableA).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
- rollbackB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B);
- assertRollbackInfoForAandB(rollbackB);
+ availableB = waitForAvailableRollback(TestApp.B);
+ assertThat(availableB).isNotNull();
+ assertThat(availableB).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
// Rollback of B should rollback A as well
- RollbackTestUtils.rollback(rollbackB.getRollbackId());
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ RollbackUtils.rollback(availableB.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
+
+ RollbackInfo committedA = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(committedA).isNotNull();
+ assertThat(committedA).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
+
+ RollbackInfo committedB = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(committedB).isNotNull();
+ assertThat(committedB).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
+
+ // Assert they're both the same rollback
+ assertThat(committedA).hasRollbackId(committedB.getRollbackId());
+ assertThat(committedA).hasRollbackId(availableA.getRollbackId());
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -274,42 +314,49 @@
@Test
public void testRecentlyCommittedRollbackPersistence() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
// The app should now be available for rollback.
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
+ RollbackInfo available = waitForAvailableRollback(TestApp.A);
+ assertThat(available).isNotNull();
// Roll back the app.
- VersionedPackage cause = new VersionedPackage(
- "com.android.tests.rollback.testapp.Foo", 42);
- RollbackTestUtils.rollback(rollback.getRollbackId(), cause);
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ TestApp cause = new TestApp("Foo", "com.android.tests.rollback.testapp.Foo",
+ /*versionCode*/ 42, /*isApex*/ false);
+ RollbackUtils.rollback(available.getRollbackId(), cause);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
// Verify the recent rollback has been recorded.
- rollback = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, cause);
+ RollbackInfo committed = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(committed).isNotNull();
+ assertThat(committed).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(committed).causePackagesContainsExactly(cause);
// Reload the persisted data.
rm.reloadPersistedData();
// Verify the recent rollback is still recorded.
- rollback = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, cause);
+ committed = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(committed).isNotNull();
+ assertThat(committed).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(committed).causePackagesContainsExactly(cause);
+ assertThat(committed).hasRollbackId(available.getRollbackId());
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -320,10 +367,10 @@
public void testRollbackExpiresAfterLifetime() throws Exception {
long expirationTime = TimeUnit.SECONDS.toMillis(30);
long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -336,39 +383,43 @@
// Pull the new expiration time from DeviceConfig
rm.reloadPersistedData();
- // Uninstall TEST_APP_A
- RollbackTestUtils.uninstall(TEST_APP_A);
- assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ // Uninstall TestApp.A
+ Uninstall.packages(TestApp.A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
// Install v1 of the app (without rollbacks enabled).
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
// Upgrade from v1 to v2, with rollbacks enabled.
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
// Check that the rollback data has not expired
Thread.sleep(1000);
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
- // Give it a little more time, but still not the long enough to expire
+ // Give it a little more time, but still not long enough to expire
Thread.sleep(expirationTime / 2);
rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
// Check that the data has expired after the expiration time (with a buffer of 1 second)
Thread.sleep(expirationTime / 2);
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNull();
} finally {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(defaultExpirationTime), false /* makeDefault*/);
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -380,10 +431,10 @@
public void testTimeChangeDoesNotAffectLifetime() throws Exception {
long expirationTime = TimeUnit.SECONDS.toMillis(30);
long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -398,24 +449,25 @@
rm.reloadPersistedData();
// Install app A with rollback enabled
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
Thread.sleep(expirationTime / 2);
// Install app B with rollback enabled
- RollbackTestUtils.uninstall(TEST_APP_B);
- RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ Uninstall.packages(TestApp.B);
+ Install.single(TestApp.B1).commit();
+ Install.single(TestApp.B2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
+
// 1 second buffer
Thread.sleep(1000);
try {
// Change the time
- RollbackTestUtils.forwardTimeBy(expirationTime);
+ RollbackUtils.forwardTimeBy(expirationTime);
// 1 second buffer to allow Rollback Manager to handle time change before loading
// persisted data
@@ -427,24 +479,31 @@
// Wait until rollback for app A has expired
// This will trigger an expiration run that should expire app A but not B
Thread.sleep(expirationTime / 2);
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ RollbackInfo rollback =
+ getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNull();
// Rollback for app B should not be expired
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_B);
- assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollback);
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.B);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.B2).to(TestApp.B1));
// Wait until rollback for app B has expired
Thread.sleep(expirationTime / 2);
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B));
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.B);
+ // Rollback should be expired by now
+ assertThat(rollback).isNull();
} finally {
- RollbackTestUtils.forwardTimeBy(-expirationTime);
+ RollbackUtils.forwardTimeBy(-expirationTime);
}
} finally {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(defaultExpirationTime), false /* makeDefault*/);
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -455,30 +514,30 @@
@Test
public void testRollbackExpiration() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
// The app should now be available for rollback.
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
// Expire the rollback.
- rm.expireRollbackForPackage(TEST_APP_A);
+ rm.expireRollbackForPackage(TestApp.A);
// The rollback should no longer be available.
- assertNull(getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A));
+ assertThat(getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A)).isNull();
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -488,24 +547,22 @@
@Test
public void testUserDataRollback() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- processUserData(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- processUserData(TEST_APP_A);
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ processUserData(TestApp.A);
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ processUserData(TestApp.A);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- RollbackTestUtils.rollback(rollback.getRollbackId());
- processUserData(TEST_APP_A);
+ RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(rollback.getRollbackId());
+ processUserData(TestApp.A);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -515,30 +572,23 @@
@Test
public void testRollbackWithSplits() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.installSplit(false,
- "RollbackTestAppASplitV1.apk",
- "RollbackTestAppASplitV1_anydpi.apk");
- processUserData(TEST_APP_A);
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.ASplit1).commit();
+ processUserData(TestApp.A);
- RollbackTestUtils.installSplit(true,
- "RollbackTestAppASplitV2.apk",
- "RollbackTestAppASplitV2_anydpi.apk");
- processUserData(TEST_APP_A);
+ Install.single(TestApp.ASplit2).setEnableRollback().commit();
+ processUserData(TestApp.A);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertNotNull(rollback);
- RollbackTestUtils.rollback(rollback.getRollbackId());
- processUserData(TEST_APP_A);
+ RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(rollback.getRollbackId());
+ processUserData(TestApp.A);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -559,7 +609,7 @@
// Confirm that we really haven't received the broadcast.
// TODO: How long to wait for the expected timeout?
- assertNull(broadcastReceiver.poll(5, TimeUnit.SECONDS));
+ assertThat(broadcastReceiver.poll(5, TimeUnit.SECONDS)).isNull();
// TODO: Do we need to do this? Do we need to ensure this is always
// called, even when the test fails?
@@ -573,48 +623,47 @@
@Test
public void testMultipleRollbackAvailable() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
// Prep installation of the test apps.
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackTestUtils.uninstall(TEST_APP_B);
- RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ Uninstall.packages(TestApp.B);
+ Install.single(TestApp.B1).commit();
+ Install.single(TestApp.B2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
// Both test apps should now be available for rollback, and the
// RollbackInfo returned for the rollbacks should be correct.
- RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+ RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
+ assertThat(rollbackA).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
- RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_B);
- assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+ RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
+ assertThat(rollbackB).packagesContainsExactly(
+ Rollback.from(TestApp.B2).to(TestApp.B1));
// Executing rollback should roll back the correct package.
- RollbackTestUtils.rollback(rollbackA.getRollbackId());
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ RollbackUtils.rollback(rollbackA.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackTestUtils.rollback(rollbackB.getRollbackId());
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ RollbackUtils.rollback(rollbackB.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -626,7 +675,7 @@
public void testManageRollbacksPermission() throws Exception {
// We shouldn't be allowed to call any of the RollbackManager APIs
// without the MANAGE_ROLLBACKS permission.
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
try {
rm.getAvailableRollbacks();
@@ -659,7 +708,7 @@
}
try {
- rm.expireRollbackForPackage(TEST_APP_A);
+ rm.expireRollbackForPackage(TestApp.A);
fail("expected SecurityException");
} catch (SecurityException e) {
// Expected.
@@ -673,26 +722,27 @@
@Test
public void testEnableRollbackPermission() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES);
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+ Install.single(TestApp.A2).setEnableRollback().commit();
// We expect v2 of the app was installed, but rollback has not
// been enabled.
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(
+ getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -703,25 +753,26 @@
@Test
public void testNonModuleEnableRollback() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS);
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+ Install.single(TestApp.A2).setEnableRollback().commit();
// We expect v2 of the app was installed, but rollback has not
// been enabled because the test app is not a module.
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(
+ getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -731,54 +782,53 @@
@Test
public void testMultiPackage() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
// Prep installation of the test apps.
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.uninstall(TEST_APP_B);
- RollbackTestUtils.installMultiPackage(false,
- "RollbackTestAppAv1.apk",
- "RollbackTestAppBv1.apk");
- processUserData(TEST_APP_A);
- processUserData(TEST_APP_B);
- RollbackTestUtils.installMultiPackage(true,
- "RollbackTestAppAv2.apk",
- "RollbackTestAppBv2.apk");
- processUserData(TEST_APP_A);
- processUserData(TEST_APP_B);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ Uninstall.packages(TestApp.A, TestApp.B);
+ Install.multi(TestApp.A1, TestApp.B1).commit();
+ processUserData(TestApp.A);
+ processUserData(TestApp.B);
+ Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
+ processUserData(TestApp.A);
+ processUserData(TestApp.B);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
- // TEST_APP_A should now be available for rollback.
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoForAandB(rollback);
+ // TestApp.A should now be available for rollback.
+ RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
// Rollback the app. It should cause both test apps to be rolled
// back.
- RollbackTestUtils.rollback(rollback.getRollbackId());
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ RollbackUtils.rollback(rollback.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
// We should see recent rollbacks listed for both A and B.
Thread.sleep(1000);
RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_B);
- assertRollbackInfoForAandB(rollbackB);
+ rm.getRecentlyCommittedRollbacks(), TestApp.B);
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1),
+ Rollback.from(TestApp.B2).to(TestApp.B1));
- assertEquals(rollbackA.getRollbackId(), rollbackB.getRollbackId());
+ assertThat(rollbackA).hasRollbackId(rollbackB.getRollbackId());
- processUserData(TEST_APP_A);
- processUserData(TEST_APP_B);
+ processUserData(TestApp.A);
+ processUserData(TestApp.B);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -790,31 +840,27 @@
@Test
public void testMultiPackageEnableFail() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.uninstall(TEST_APP_B);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-
+ Uninstall.packages(TestApp.A, TestApp.B);
+ Install.single(TestApp.A1).commit();
// We should fail to enable rollback here because TestApp B is not
// already installed.
- RollbackTestUtils.installMultiPackage(true,
- "RollbackTestAppAv2.apk",
- "RollbackTestAppBv2.apk");
+ Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
- assertNull(getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A));
- assertNull(getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_B));
+ assertThat(getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A)).isNull();
+ assertThat(getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.B)).isNull();
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -825,30 +871,33 @@
*/
public void testSameVersionUpdate() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ Install.single(TestApp.ACrashing2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback);
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A2));
- RollbackTestUtils.rollback(rollback.getRollbackId());
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ RollbackUtils.rollback(rollback.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
rollback = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback);
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A2));
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -857,60 +906,54 @@
*/
@Test
public void testBadUpdateRollback() throws Exception {
- BroadcastReceiver crashCountReceiver = null;
Context context = InstrumentationRegistry.getContext();
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.KILL_BACKGROUND_PROCESSES,
+ Manifest.permission.FORCE_STOP_PACKAGES,
Manifest.permission.RESTART_PACKAGES);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
// Prep installation of the test apps.
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A, TestApp.B);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.ACrashing2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackTestUtils.uninstall(TEST_APP_B);
- RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ Install.single(TestApp.B1).commit();
+ Install.single(TestApp.B2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
// Both test apps should now be available for rollback, and the
// targetPackage returned for rollback should be correct.
- RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+ RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
+ assertThat(rollbackA).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
- RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_B);
- assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+ RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
+ assertThat(rollbackB).packagesContainsExactly(
+ Rollback.from(TestApp.B2).to(TestApp.B1));
// Register rollback committed receiver
RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver();
- // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
- crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5);
+ // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
// Verify we received a broadcast for the rollback.
rollbackReceiver.take();
- // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ // TestApp.A is automatically rolled back by the RollbackPackageHealthObserver
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
// Instrumented app is still the package installer
- String installer = context.getPackageManager().getInstallerPackageName(TEST_APP_A);
- assertEquals(INSTRUMENTED_APP, installer);
- // TEST_APP_B is untouched
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ String installer = context.getPackageManager().getInstallerPackageName(TestApp.A);
+ assertThat(installer).isEqualTo(INSTRUMENTED_APP);
+ // TestApp.B is untouched
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
- if (crashCountReceiver != null) {
- context.unregisterReceiver(crashCountReceiver);
- }
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -920,31 +963,31 @@
@Test
public void testRollForwardRace() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+ RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
// Install a new version of package A, then immediately rollback
// the previous version. We expect the rollback to fail, because
// it is no longer available.
// There are a couple different ways this could fail depending on
// thread interleaving, so don't ignore flaky failures.
- RollbackTestUtils.install("RollbackTestAppAv3.apk", false);
+ Install.single(TestApp.A3).commit();
try {
- RollbackTestUtils.rollback(rollback.getRollbackId());
+ RollbackUtils.rollback(rollback.getRollbackId());
// Note: Don't ignore flaky failures here.
fail("Expected rollback to fail, but it did not.");
} catch (AssertionError e) {
@@ -953,9 +996,9 @@
}
// Note: Don't ignore flaky failures here.
- assertEquals(3, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(3);
} finally {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
}
@@ -963,7 +1006,7 @@
@Ignore("b/136605788")
public void testEnableRollbackTimeoutFailsRollback() throws Exception {
try {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -973,36 +1016,32 @@
//setting the timeout to a very short amount that will definitely be triggered
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
- Long.toString(1), false /* makeDefault*/);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ Long.toString(0), false /* makeDefault*/);
+ RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackTestUtils.uninstall(TEST_APP_A);
- RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
- RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ waitForUnavailableRollback(TestApp.A);
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ // Block the RollbackManager to make extra sure it will not be
+ // able to enable the rollback in time.
+ rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(1));
+ Install.single(TestApp.A2).setEnableRollback().commit();
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+ // Give plenty of time for RollbackManager to unblock and attempt
+ // to make the rollback available before asserting that the
+ // rollback was not made available.
+ Thread.sleep(TimeUnit.SECONDS.toMillis(2));
+ assertThat(
+ getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
} finally {
//setting the timeout back to default
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
null, false /* makeDefault*/);
- RollbackTestUtils.dropShellPermissionIdentity();
- }
- }
-
- // Helper function to test that the given rollback info is a rollback for
- // the atomic set {A2, B2} -> {A1, B1}.
- private void assertRollbackInfoForAandB(RollbackInfo rollback) {
- assertNotNull(rollback);
- assertEquals(2, rollback.getPackages().size());
- if (TEST_APP_A.equals(rollback.getPackages().get(0).getPackageName())) {
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(0));
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(1));
- } else {
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(0));
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(1));
+ InstallUtils.dropShellPermissionIdentity();
}
}
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
deleted file mode 100644
index a9e20cd..0000000
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.rollback;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.content.rollback.PackageRollbackInfo;
-import android.content.rollback.RollbackInfo;
-import android.content.rollback.RollbackManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.SynchronousQueue;
-
-/**
- * Utilities to facilitate testing rollbacks.
- */
-class RollbackTestUtils {
-
- private static final String TAG = "RollbackTest";
-
- static RollbackManager getRollbackManager() {
- Context context = InstrumentationRegistry.getContext();
- RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
- if (rm == null) {
- throw new AssertionError("Failed to get RollbackManager");
- }
- return rm;
- }
-
- private static void setTime(long millis) {
- Context context = InstrumentationRegistry.getContext();
- AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- am.setTime(millis);
- }
-
- static void forwardTimeBy(long offsetMillis) {
- setTime(System.currentTimeMillis() + offsetMillis);
- Log.i(TAG, "Forwarded time on device by " + offsetMillis + " millis");
- }
-
- /**
- * Returns the version of the given package installed on device.
- * Returns -1 if the package is not currently installed.
- */
- static long getInstalledVersion(String packageName) {
- PackageInfo pi = getPackageInfo(packageName);
- if (pi == null) {
- return -1;
- } else {
- return pi.getLongVersionCode();
- }
- }
-
- private static boolean isSystemAppWithoutUpdate(String packageName) {
- PackageInfo pi = getPackageInfo(packageName);
- if (pi == null) {
- return false;
- } else {
- return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
- && ((pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0);
- }
- }
-
- private static PackageInfo getPackageInfo(String packageName) {
- Context context = InstrumentationRegistry.getContext();
- PackageManager pm = context.getPackageManager();
- try {
- return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- }
- }
-
- private static void assertStatusSuccess(Intent result) {
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == -1) {
- throw new AssertionError("PENDING USER ACTION");
- } else if (status > 0) {
- String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
- }
- }
-
- /**
- * Uninstalls the given package.
- * Does nothing if the package is not installed.
- * @throws AssertionError if package can't be uninstalled.
- */
- static void uninstall(String packageName) throws InterruptedException, IOException {
- // No need to uninstall if the package isn't installed or is installed on /system.
- if (getInstalledVersion(packageName) == -1 || isSystemAppWithoutUpdate(packageName)) {
- return;
- }
-
- Context context = InstrumentationRegistry.getContext();
- PackageManager packageManager = context.getPackageManager();
- PackageInstaller packageInstaller = packageManager.getPackageInstaller();
- packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
- }
-
- /**
- * Commit the given rollback.
- * @throws AssertionError if the rollback fails.
- */
- static void rollback(int rollbackId, VersionedPackage... causePackages)
- throws InterruptedException {
- RollbackManager rm = getRollbackManager();
- rm.commitRollback(rollbackId, Arrays.asList(causePackages),
- LocalIntentSender.getIntentSender());
- Intent result = LocalIntentSender.getIntentSenderResult();
- int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
- RollbackManager.STATUS_FAILURE);
- if (status != RollbackManager.STATUS_SUCCESS) {
- String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message);
- }
- }
-
- /**
- * Installs the apk with the given name.
- *
- * @param resourceName name of class loader resource for the apk to
- * install.
- * @param enableRollback if rollback should be enabled.
- * @throws AssertionError if the installation fails.
- */
- static void install(String resourceName, boolean enableRollback)
- throws InterruptedException, IOException {
- installSplit(enableRollback, resourceName);
- }
-
- /**
- * Installs the apk with the given name and its splits.
- *
- * @param enableRollback if rollback should be enabled.
- * @param resourceNames names of class loader resources for the apk and
- * its splits to install.
- * @throws AssertionError if the installation fails.
- */
- static void installSplit(boolean enableRollback, String... resourceNames)
- throws InterruptedException, IOException {
- Context context = InstrumentationRegistry.getContext();
- PackageInstaller.Session session = null;
- PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- params.setEnableRollback(enableRollback);
- int sessionId = packageInstaller.createSession(params);
- session = packageInstaller.openSession(sessionId);
-
- ClassLoader loader = RollbackTest.class.getClassLoader();
- for (String resourceName : resourceNames) {
- try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
- InputStream is = loader.getResourceAsStream(resourceName);) {
- byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- packageInSession.write(buffer, 0, n);
- }
- }
- }
-
- // Commit the session (this will start the installation workflow).
- session.commit(LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
- }
-
- /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
- private static void launchPackage(String packageName)
- throws InterruptedException, IOException {
- Context context = InstrumentationRegistry.getContext();
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setPackage(packageName);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- context.startActivity(intent);
- }
-
- /**
- * Installs the APKs or APEXs with the given resource names as an atomic
- * set. A resource is assumed to be an APEX if it has the .apex extension.
- * <p>
- * In case of staged installs, this function will return succesfully after
- * the staged install has been committed and is ready for the device to
- * reboot.
- *
- * @param staged if the rollback should be staged.
- * @param enableRollback if rollback should be enabled.
- * @param resourceNames names of the class loader resource for the apks to
- * install.
- * @throws AssertionError if the installation fails.
- */
- private static void install(boolean staged, boolean enableRollback,
- String... resourceNames) throws InterruptedException, IOException {
- Context context = InstrumentationRegistry.getContext();
- PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
-
- PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- multiPackageParams.setMultiPackage();
- if (staged) {
- multiPackageParams.setStaged();
- }
- // TODO: Do we set this on the parent params, the child params, or
- // both?
- multiPackageParams.setEnableRollback(enableRollback);
- int multiPackageId = packageInstaller.createSession(multiPackageParams);
- PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
-
- for (String resourceName : resourceNames) {
- PackageInstaller.Session session = null;
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- if (staged) {
- params.setStaged();
- }
- if (resourceName.endsWith(".apex")) {
- params.setInstallAsApex();
- }
- params.setEnableRollback(enableRollback);
- int sessionId = packageInstaller.createSession(params);
- session = packageInstaller.openSession(sessionId);
-
- ClassLoader loader = RollbackTest.class.getClassLoader();
- try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
- InputStream is = loader.getResourceAsStream(resourceName);) {
- byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- packageInSession.write(buffer, 0, n);
- }
- }
- multiPackage.addChildSessionId(sessionId);
- }
-
- // Commit the session (this will start the installation workflow).
- multiPackage.commit(LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-
- if (staged) {
- waitForSessionReady(multiPackageId);
- }
- }
-
- /**
- * Installs the apks with the given resource names as an atomic set.
- *
- * @param enableRollback if rollback should be enabled.
- * @param resourceNames names of the class loader resource for the apks to
- * install.
- * @throws AssertionError if the installation fails.
- */
- static void installMultiPackage(boolean enableRollback, String... resourceNames)
- throws InterruptedException, IOException {
- install(false, enableRollback, resourceNames);
- }
-
- /**
- * Installs the APKs or APEXs with the given resource names as a staged
- * atomic set. A resource is assumed to be an APEX if it has the .apex
- * extension.
- *
- * @param enableRollback if rollback should be enabled.
- * @param resourceNames names of the class loader resource for the apks to
- * install.
- * @throws AssertionError if the installation fails.
- */
- static void installStaged(boolean enableRollback, String... resourceNames)
- throws InterruptedException, IOException {
- install(true, enableRollback, resourceNames);
- }
-
- static void adoptShellPermissionIdentity(String... permissions) {
- InstrumentationRegistry
- .getInstrumentation()
- .getUiAutomation()
- .adoptShellPermissionIdentity(permissions);
- }
-
- static void dropShellPermissionIdentity() {
- InstrumentationRegistry
- .getInstrumentation()
- .getUiAutomation()
- .dropShellPermissionIdentity();
- }
-
- /**
- * Returns the RollbackInfo with a given package in the list of rollbacks.
- * Throws an assertion failure if there is more than one such rollback
- * info. Returns null if there are no such rollback infos.
- */
- static RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
- String packageName) {
- RollbackInfo found = null;
- for (RollbackInfo rollback : rollbacks) {
- for (PackageRollbackInfo info : rollback.getPackages()) {
- if (packageName.equals(info.getPackageName())) {
- assertNull(found);
- found = rollback;
- break;
- }
- }
- }
- return found;
- }
-
- /**
- * Asserts that the given PackageRollbackInfo has the expected package
- * name and versions.
- */
- static void assertPackageRollbackInfoEquals(String packageName,
- long versionRolledBackFrom, long versionRolledBackTo,
- PackageRollbackInfo info) {
- assertEquals(packageName, info.getPackageName());
- assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
- assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
- assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
- assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
- }
-
- /**
- * Asserts that the given RollbackInfo has the given packages with expected
- * package names and all are rolled to and from the same given versions.
- */
- static void assertRollbackInfoEquals(String[] packageNames,
- long versionRolledBackFrom, long versionRolledBackTo,
- RollbackInfo info, VersionedPackage... causePackages) {
- assertNotNull(info);
- assertEquals(packageNames.length, info.getPackages().size());
- int foundPackages = 0;
- for (String packageName : packageNames) {
- for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
- if (packageName.equals(pkgRollbackInfo.getPackageName())) {
- foundPackages++;
- assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom,
- versionRolledBackTo, pkgRollbackInfo);
- break;
- }
- }
- }
- assertEquals(packageNames.length, foundPackages);
- assertEquals(causePackages.length, info.getCausePackages().size());
- for (int i = 0; i < causePackages.length; ++i) {
- assertEquals(causePackages[i].getPackageName(),
- info.getCausePackages().get(i).getPackageName());
- assertEquals(causePackages[i].getLongVersionCode(),
- info.getCausePackages().get(i).getLongVersionCode());
- }
- }
-
- /**
- * Asserts that the given RollbackInfo has a single package with expected
- * package name and versions.
- */
- static void assertRollbackInfoEquals(String packageName,
- long versionRolledBackFrom, long versionRolledBackTo,
- RollbackInfo info, VersionedPackage... causePackages) {
- String[] packageNames = {packageName};
- assertRollbackInfoEquals(packageNames, versionRolledBackFrom, versionRolledBackTo, info,
- causePackages);
- }
-
- /**
- * Waits for the given session to be marked as ready.
- * Throws an assertion if the session fails.
- */
- static void waitForSessionReady(int sessionId) {
- BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
- BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- PackageInstaller.SessionInfo info =
- intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
- if (info != null && info.getSessionId() == sessionId) {
- if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
- try {
- sessionStatus.put(info);
- } catch (InterruptedException e) {
- Log.e(TAG, "Failed to put session info.", e);
- }
- }
- }
- }
- };
- IntentFilter sessionUpdatedFilter =
- new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
-
- Context context = InstrumentationRegistry.getContext();
- context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
-
- PackageInstaller installer = context.getPackageManager().getPackageInstaller();
- PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
-
- try {
- if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
- sessionStatus.put(info);
- }
-
- info = sessionStatus.take();
- context.unregisterReceiver(sessionUpdatedReceiver);
- if (info.isStagedSessionFailed()) {
- throw new AssertionError(info.getStagedSessionErrorMessage());
- }
- } catch (InterruptedException e) {
- throw new AssertionError(e);
- }
- }
-
- private static final String NO_RESPONSE = "NO RESPONSE";
-
- /**
- * Calls into the test app to process user data.
- * Asserts if the user data could not be processed or was version
- * incompatible with the previously processed user data.
- */
- static void processUserData(String packageName) {
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(packageName,
- "com.android.tests.rollback.testapp.ProcessUserData"));
- Context context = InstrumentationRegistry.getContext();
-
- HandlerThread handlerThread = new HandlerThread("RollbackTestHandlerThread");
- handlerThread.start();
-
- // It can sometimes take a while after rollback before the app will
- // receive this broadcast, so try a few times in a loop.
- String result = NO_RESPONSE;
- for (int i = 0; result.equals(NO_RESPONSE) && i < 5; ++i) {
- BlockingQueue<String> resultQueue = new LinkedBlockingQueue<>();
- context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (getResultCode() == 1) {
- resultQueue.add("OK");
- } else {
- // If the test app doesn't receive the broadcast or
- // fails to set the result data, then getResultData
- // here returns the initial NO_RESPONSE data passed to
- // the sendOrderedBroadcast call.
- resultQueue.add(getResultData());
- }
- }
- }, new Handler(handlerThread.getLooper()), 0, NO_RESPONSE, null);
-
- try {
- result = resultQueue.take();
- } catch (InterruptedException e) {
- throw new AssertionError(e);
- }
- }
-
- handlerThread.quit();
- if (!"OK".equals(result)) {
- fail(result);
- }
- }
-
- /**
- * Return the rollback info for a recently committed rollback, by matching the rollback id, or
- * return null if no matching rollback is found.
- */
- static RollbackInfo getRecentlyCommittedRollbackInfoById(int getRollbackId) {
- for (RollbackInfo info : getRollbackManager().getRecentlyCommittedRollbacks()) {
- if (info.getRollbackId() == getRollbackId) {
- return info;
- }
- }
- return null;
- }
-
- /**
- * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least
- * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered.
- */
- static BroadcastReceiver sendCrashBroadcast(Context context, String packageName, int count)
- throws InterruptedException, IOException {
- BlockingQueue<Integer> crashQueue = new SynchronousQueue<>();
- IntentFilter crashCountFilter = new IntentFilter();
- crashCountFilter.addAction("com.android.tests.rollback.CRASH");
- crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT);
-
- BroadcastReceiver crashCountReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- try {
- // Sleep long enough for packagewatchdog to be notified of crash
- Thread.sleep(1000);
- // Kill app and close AppErrorDialog
- ActivityManager am = context.getSystemService(ActivityManager.class);
- am.killBackgroundProcesses(packageName);
- // Allow another package launch
- crashQueue.put(intent.getIntExtra("count", 0));
- } catch (InterruptedException e) {
- fail("Failed to communicate with test app");
- }
- }
- };
- context.registerReceiver(crashCountReceiver, crashCountFilter);
-
- do {
- launchPackage(packageName);
- } while(crashQueue.take() < count);
- return crashCountReceiver;
- }
-}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 1a29c4c..9e6ac8e 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -16,26 +16,34 @@
package com.android.tests.rollback;
-import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
-import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
+import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
+import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
import android.Manifest;
-import android.content.BroadcastReceiver;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.VersionedPackage;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
+import android.text.TextUtils;
import androidx.test.InstrumentationRegistry;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+import com.android.cts.rollback.lib.Rollback;
+import com.android.cts.rollback.lib.RollbackUtils;
+import com.android.internal.R;
import org.junit.After;
import org.junit.Before;
@@ -54,23 +62,21 @@
@RunWith(JUnit4.class)
public class StagedRollbackTest {
- private static final String TAG = "RollbackTest";
- private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
- private static final String TEST_APP_A_V1 = "RollbackTestAppAv1.apk";
- private static final String TEST_APP_A_CRASHING_V2 = "RollbackTestAppACrashingV2.apk";
private static final String NETWORK_STACK_CONNECTOR_CLASS =
"android.net.INetworkStackConnector";
+ private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName();
+
/**
* Adopts common shell permissions needed for rollback tests.
*/
@Before
public void adoptShellPermissions() {
- RollbackTestUtils.adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.KILL_BACKGROUND_PROCESSES);
+ Manifest.permission.FORCE_STOP_PACKAGES);
}
/**
@@ -78,7 +84,7 @@
*/
@After
public void dropShellPermissions() {
- RollbackTestUtils.dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
/**
@@ -87,14 +93,14 @@
*/
@Test
public void testBadApkOnlyEnableRollback() throws Exception {
- RollbackTestUtils.uninstall(TEST_APP_A);
- assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ Uninstall.packages(TestApp.A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
- RollbackTestUtils.install(TEST_APP_A_V1, false);
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- RollbackTestUtils.processUserData(TEST_APP_A);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
- RollbackTestUtils.installStaged(true, TEST_APP_A_CRASHING_V2);
+ Install.single(TestApp.ACrashing2).setEnableRollback().setStaged().commit();
// At this point, the host test driver will reboot the device and run
// testBadApkOnlyConfirmEnableRollback().
@@ -106,14 +112,16 @@
*/
@Test
public void testBadApkOnlyConfirmEnableRollback() throws Exception {
- assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- RollbackTestUtils.processUserData(TEST_APP_A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ InstallUtils.processUserData(TestApp.A);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
- assertTrue(rollback.isStaged());
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(rollback.isStaged()).isTrue();
// At this point, the host test driver will run
// testBadApkOnlyTriggerRollback().
@@ -126,18 +134,8 @@
*/
@Test
public void testBadApkOnlyTriggerRollback() throws Exception {
- BroadcastReceiver crashCountReceiver = null;
- Context context = InstrumentationRegistry.getContext();
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
-
- try {
- // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
- crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5);
- } finally {
- if (crashCountReceiver != null) {
- context.unregisterReceiver(crashCountReceiver);
- }
- }
+ // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
// We expect the device to be rebooted automatically. Wait for that to
// happen. At that point, the host test driver will wait for the
@@ -153,48 +151,80 @@
*/
@Test
public void testBadApkOnlyConfirmRollback() throws Exception {
- assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- RollbackTestUtils.processUserData(TEST_APP_A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
- assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, new VersionedPackage(TEST_APP_A, 2));
- assertTrue(rollback.isStaged());
- assertNotEquals(-1, rollback.getCommittedSessionId());
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(rollback).causePackagesContainsExactly(TestApp.ACrashing2);
+ assertThat(rollback).isStaged();
+ assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1);
}
@Test
public void resetNetworkStack() throws Exception {
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
rm.expireRollbackForPackage(networkStack);
- RollbackTestUtils.uninstall(networkStack);
+ Uninstall.packages(networkStack);
- assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- networkStack));
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ networkStack)).isNull();
+ }
+
+ @Test
+ public void installModuleMetadataPackage() throws Exception {
+ resetModuleMetadataPackage();
+ Context context = InstrumentationRegistry.getContext();
+ PackageInfo metadataPackageInfo = context.getPackageManager().getPackageInfo(
+ MODULE_META_DATA_PACKAGE, 0);
+ String metadataApkPath = metadataPackageInfo.applicationInfo.sourceDir;
+ assertThat(metadataApkPath).isNotNull();
+ assertThat(metadataApkPath).isNotEqualTo("");
+
+ runShellCommand("pm install "
+ + "-r --enable-rollback --staged --wait "
+ + metadataApkPath);
}
@Test
public void assertNetworkStackRollbackAvailable() throws Exception {
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- assertNotNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- getNetworkStackPackageName()));
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ getNetworkStackPackageName())).isNotNull();
}
@Test
public void assertNetworkStackRollbackCommitted() throws Exception {
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- assertNotNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- getNetworkStackPackageName()));
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+ getNetworkStackPackageName())).isNotNull();
}
@Test
public void assertNoNetworkStackRollbackCommitted() throws Exception {
- RollbackManager rm = RollbackTestUtils.getRollbackManager();
- assertNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- getNetworkStackPackageName()));
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+ getNetworkStackPackageName())).isNull();
+ }
+
+ @Test
+ public void assertModuleMetadataRollbackAvailable() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ MODULE_META_DATA_PACKAGE)).isNotNull();
+ }
+
+ @Test
+ public void assertModuleMetadataRollbackCommitted() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+ MODULE_META_DATA_PACKAGE)).isNotNull();
}
private String getNetworkStackPackageName() {
@@ -203,4 +233,65 @@
InstrumentationRegistry.getContext().getPackageManager(), 0);
return comp.getPackageName();
}
+
+ @Test
+ public void testPreviouslyAbandonedRollbacksEnableRollback() throws Exception {
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+
+ int sessionId = Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+ PackageInstaller pi = InstrumentationRegistry.getContext().getPackageManager()
+ .getPackageInstaller();
+ pi.abandonSession(sessionId);
+
+ // Remove the first intent sender result, so that the next staged install session does not
+ // erroneously think that it has itself been abandoned.
+ // TODO(b/136260017): Restructure LocalIntentSender to negate the need for this step.
+ LocalIntentSender.getIntentSenderResult();
+ Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+ }
+
+ @Test
+ public void testPreviouslyAbandonedRollbacksCommitRollback() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ InstallUtils.processUserData(TestApp.A);
+
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ RollbackUtils.rollback(rollback.getRollbackId());
+ }
+
+ @Test
+ public void testPreviouslyAbandonedRollbacksCheckUserdataRollback() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+ Uninstall.packages(TestApp.A);
+ }
+
+ @Nullable
+ private static String getModuleMetadataPackageName() {
+ String packageName = InstrumentationRegistry.getContext().getResources().getString(
+ R.string.config_defaultModuleMetadataProvider);
+ if (TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+ return packageName;
+ }
+
+ private void resetModuleMetadataPackage() {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+
+ assertThat(MODULE_META_DATA_PACKAGE).isNotNull();
+ rm.expireRollbackForPackage(MODULE_META_DATA_PACKAGE);
+
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ MODULE_META_DATA_PACKAGE)).isNull();
+ }
+
+ private void runShellCommand(String cmd) {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .executeShellCommand(cmd);
+ }
}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index b767b08..f74aaf3 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -29,11 +29,15 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.TimeUnit;
+
/**
* Runs the staged rollback tests.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedRollbackTest extends BaseHostJUnit4Test {
+ private static final int NATIVE_CRASHES_THRESHOLD = 5;
+
/**
* Runs the given phase of a test by calling into the device.
* Throws an exception if the test phase fails.
@@ -84,6 +88,35 @@
runPhase("testBadApkOnlyConfirmRollback");
}
+ @Test
+ public void testNativeWatchdogTriggersRollback() throws Exception {
+ //Stage install ModuleMetadata package - this simulates a Mainline module update
+ runPhase("installModuleMetadataPackage");
+
+ // Reboot device to activate staged package
+ getDevice().reboot();
+ getDevice().waitForDeviceAvailable();
+
+ runPhase("assertModuleMetadataRollbackAvailable");
+
+ // crash system_server enough times to trigger a rollback
+ crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
+
+ // Rollback should be committed automatically now.
+ // Give time for rollback to be committed. This could take a while,
+ // because we need all of the following to happen:
+ // 1. system_server comes back up and boot completes.
+ // 2. Rollback health observer detects updatable crashing signal.
+ // 3. Staged rollback session becomes ready.
+ // 4. Device actually reboots.
+ // So we give a generous timeout here.
+ assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ getDevice().waitForDeviceAvailable();
+
+ // verify rollback committed
+ runPhase("assertModuleMetadataRollbackCommitted");
+ }
+
/**
* Tests failed network health check triggers watchdog staged rollbacks.
*/
@@ -167,6 +200,32 @@
runPhase("assertNoNetworkStackRollbackCommitted");
}
+ /**
+ * Tests rolling back user data where there are multiple rollbacks for that package.
+ */
+ @Test
+ public void testPreviouslyAbandonedRollbacks() throws Exception {
+ runPhase("testPreviouslyAbandonedRollbacksEnableRollback");
+ getDevice().reboot();
+ runPhase("testPreviouslyAbandonedRollbacksCommitRollback");
+ getDevice().reboot();
+ runPhase("testPreviouslyAbandonedRollbacksCheckUserdataRollback");
+ }
+
+ private void crashProcess(String processName, int numberOfCrashes) throws Exception {
+ String pid = "";
+ String lastPid = "invalid";
+ for (int i = 0; i < numberOfCrashes; ++i) {
+ // This condition makes sure before we kill the process, the process is running AND
+ // the last crash was finished.
+ while ("".equals(pid) || lastPid.equals(pid)) {
+ pid = getDevice().executeShellCommand("pidof " + processName);
+ }
+ getDevice().executeShellCommand("kill " + pid);
+ lastPid = pid;
+ }
+ }
+
private String getNetworkStackPath() throws DeviceNotAvailableException {
// Find the NetworkStack path (can be NetworkStack.apk or NetworkStackNext.apk)
return getDevice().executeShellCommand("ls /system/priv-app/NetworkStack*/*.apk");
diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING
index 6be93a0..fefde5b 100644
--- a/tests/RollbackTest/TEST_MAPPING
+++ b/tests/RollbackTest/TEST_MAPPING
@@ -5,6 +5,9 @@
},
{
"name": "StagedRollbackTest"
+ },
+ {
+ "name": "MultiUserRollbackTest"
}
]
}
diff --git a/tests/RollbackTest/TestApp/ACrashingV2.xml b/tests/RollbackTest/TestApp/ACrashingV2.xml
deleted file mode 100644
index 77bfd4e..0000000
--- a/tests/RollbackTest/TestApp/ACrashingV2.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.rollback.testapp.A"
- android:versionCode="2"
- android:versionName="2.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="Rollback Test App A v2">
- <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
- android:exported="true" />
- <activity android:name="com.android.tests.rollback.testapp.CrashingMainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT"/>
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Av1.xml b/tests/RollbackTest/TestApp/Av1.xml
deleted file mode 100644
index 63729fb..0000000
--- a/tests/RollbackTest/TestApp/Av1.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.rollback.testapp.A"
- android:versionCode="1"
- android:versionName="1.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="Rollback Test App A v1">
- <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
- android:exported="true" />
- <activity android:name="com.android.tests.rollback.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Av2.xml b/tests/RollbackTest/TestApp/Av2.xml
deleted file mode 100644
index f0e909f..0000000
--- a/tests/RollbackTest/TestApp/Av2.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.rollback.testapp.A"
- android:versionCode="2"
- android:versionName="2.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="Rollback Test App A v2">
- <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
- android:exported="true" />
- <activity android:name="com.android.tests.rollback.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Av3.xml b/tests/RollbackTest/TestApp/Av3.xml
deleted file mode 100644
index 9725c9f7..0000000
--- a/tests/RollbackTest/TestApp/Av3.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.rollback.testapp.A"
- android:versionCode="3"
- android:versionName="3.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="Rollback Test App A v3">
- <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
- android:exported="true" />
- <activity android:name="com.android.tests.rollback.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv1.xml b/tests/RollbackTest/TestApp/Bv1.xml
deleted file mode 100644
index ca9c2ec..0000000
--- a/tests/RollbackTest/TestApp/Bv1.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.rollback.testapp.B"
- android:versionCode="1"
- android:versionName="1.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="Rollback Test App B v1">
- <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
- android:exported="true" />
- <activity android:name="com.android.tests.rollback.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv2.xml b/tests/RollbackTest/TestApp/Bv2.xml
deleted file mode 100644
index bd3e613..0000000
--- a/tests/RollbackTest/TestApp/Bv2.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.rollback.testapp.B"
- android:versionCode="2"
- android:versionName="2.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="Rollback Test App B v2">
- <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
- android:exported="true" />
- <activity android:name="com.android.tests.rollback.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml
deleted file mode 100644
index 90d3da2..0000000
--- a/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<resources>
- <integer name="split_version">1</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v1/values/values.xml b/tests/RollbackTest/TestApp/res_v1/values/values.xml
deleted file mode 100644
index 0447c74..0000000
--- a/tests/RollbackTest/TestApp/res_v1/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<resources>
- <integer name="app_version">1</integer>
- <integer name="split_version">0</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml
deleted file mode 100644
index 9a1aa7f..0000000
--- a/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<resources>
- <integer name="split_version">2</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v2/values/values.xml b/tests/RollbackTest/TestApp/res_v2/values/values.xml
deleted file mode 100644
index fd988f5..0000000
--- a/tests/RollbackTest/TestApp/res_v2/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<resources>
- <integer name="app_version">2</integer>
- <integer name="split_version">0</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml
deleted file mode 100644
index f2d8992..0000000
--- a/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<resources>
- <integer name="split_version">3</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v3/values/values.xml b/tests/RollbackTest/TestApp/res_v3/values/values.xml
deleted file mode 100644
index 968168a..0000000
--- a/tests/RollbackTest/TestApp/res_v3/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<resources>
- <integer name="app_version">3</integer>
- <integer name="split_version">0</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
deleted file mode 100644
index 97958ac..0000000
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 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.tests.rollback.testapp;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-
-/**
- * A crashing test app for testing apk rollback support.
- */
-public class CrashingMainActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- incrementCountAndBroadcast();
- throw new RuntimeException("Intended force crash");
- }
-
- private void incrementCountAndBroadcast() {
- SharedPreferences preferences = getSharedPreferences("prefs", Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = preferences.edit();
- int count = preferences.getInt("crash_count", 0);
- editor.putInt("crash_count", ++count).commit();
-
- Intent intent = new Intent("com.android.tests.rollback.CRASH");
- intent.putExtra("count", count);
- sendBroadcast(intent);
- }
-}
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
deleted file mode 100644
index 9f1a060..0000000
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.rollback.testapp;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-/**
- * A test app for testing apk rollback support.
- */
-public class MainActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- try {
- new ProcessUserData().processUserData(this);
- } catch (ProcessUserData.UserDataException e) {
- throw new AssertionError("Failed to process app user data", e);
- }
- }
-}
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
deleted file mode 100644
index 38c658e..0000000
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.rollback.testapp;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Scanner;
-
-/**
- * A broadcast reciever to check for and update user app data version
- * compatibility.
- */
-public class ProcessUserData extends BroadcastReceiver {
-
- private static final String TAG = "RollbackTestApp";
-
- /**
- * Exception thrown in case of issue with user data.
- */
- public static class UserDataException extends Exception {
- public UserDataException(String message) {
- super(message);
- }
-
- public UserDataException(String message, Throwable cause) {
- super(message, cause);
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- try {
- processUserData(context);
- setResultCode(1);
- } catch (UserDataException e) {
- setResultCode(0);
- setResultData(e.getMessage());
- }
- }
-
- /**
- * Update the app's user data version to match the app version.
- *
- * @param context The application context.
- * @throws UserDataException in case of problems with app user data.
- */
- public void processUserData(Context context) throws UserDataException {
- Resources res = context.getResources();
- String packageName = context.getPackageName();
-
- int appVersionId = res.getIdentifier("app_version", "integer", packageName);
- int appVersion = res.getInteger(appVersionId);
-
- int splitVersionId = res.getIdentifier("split_version", "integer", packageName);
- int splitVersion = res.getInteger(splitVersionId);
-
- // Make sure the app version and split versions are compatible.
- if (appVersion != splitVersion) {
- throw new UserDataException("Split version " + splitVersion
- + " does not match app version " + appVersion);
- }
-
- // Read the version of the app's user data and ensure it is compatible
- // with our version of the application.
- File versionFile = new File(context.getFilesDir(), "version.txt");
- try {
- Scanner s = new Scanner(versionFile);
- int userDataVersion = s.nextInt();
- s.close();
-
- if (userDataVersion > appVersion) {
- throw new UserDataException("User data is from version " + userDataVersion
- + ", which is not compatible with this version " + appVersion
- + " of the RollbackTestApp");
- }
- } catch (FileNotFoundException e) {
- // No problem. This is a fresh install of the app or the user data
- // has been wiped.
- }
-
- // Record the current version of the app in the user data.
- try {
- PrintWriter pw = new PrintWriter(versionFile);
- pw.println(appVersion);
- pw.close();
- } catch (IOException e) {
- throw new UserDataException("Unable to write user data.", e);
- }
- }
-}
diff --git a/tests/net/java/android/net/ip/InterfaceControllerTest.java b/tests/net/java/android/net/ip/InterfaceControllerTest.java
deleted file mode 100644
index 7a56b3a..0000000
--- a/tests/net/java/android/net/ip/InterfaceControllerTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.ip;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.net.INetd;
-import android.net.InetAddresses;
-import android.net.InterfaceConfigurationParcel;
-import android.net.LinkAddress;
-import android.net.util.SharedLog;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InterfaceControllerTest {
- private static final String TEST_IFACE = "testif";
- private static final String TEST_IPV4_ADDR = "192.168.123.28";
- private static final int TEST_PREFIXLENGTH = 31;
-
- @Mock private INetd mNetd;
- @Mock private SharedLog mLog;
- @Captor private ArgumentCaptor<InterfaceConfigurationParcel> mConfigCaptor;
-
- private InterfaceController mController;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mController = new InterfaceController(TEST_IFACE, mNetd, mLog);
-
- doNothing().when(mNetd).interfaceSetCfg(mConfigCaptor.capture());
- }
-
- @Test
- public void testSetIPv4Address() throws Exception {
- mController.setIPv4Address(
- new LinkAddress(InetAddresses.parseNumericAddress(TEST_IPV4_ADDR),
- TEST_PREFIXLENGTH));
- verify(mNetd, times(1)).interfaceSetCfg(any());
- final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue();
- assertEquals(TEST_IFACE, parcel.ifName);
- assertEquals(TEST_IPV4_ADDR, parcel.ipv4Addr);
- assertEquals(TEST_PREFIXLENGTH, parcel.prefixLength);
- assertEquals("", parcel.hwAddr);
- assertArrayEquals(new String[0], parcel.flags);
- }
-
- @Test
- public void testClearIPv4Address() throws Exception {
- mController.clearIPv4Address();
- verify(mNetd, times(1)).interfaceSetCfg(any());
- final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue();
- assertEquals(TEST_IFACE, parcel.ifName);
- assertEquals("0.0.0.0", parcel.ipv4Addr);
- assertEquals(0, parcel.prefixLength);
- assertEquals("", parcel.hwAddr);
- assertArrayEquals(new String[0], parcel.flags);
- }
-}
diff --git a/tests/net/java/android/net/netlink/ConntrackMessageTest.java b/tests/net/java/android/net/netlink/ConntrackMessageTest.java
deleted file mode 100644
index 5c86757..0000000
--- a/tests/net/java/android/net/netlink/ConntrackMessageTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.net.netlink;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assume.assumeTrue;
-
-import android.system.OsConstants;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConntrackMessageTest {
- private static final boolean USING_LE = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
-
- // Example 1: TCP (192.168.43.209, 44333) -> (23.211.13.26, 443)
- public static final String CT_V4UPDATE_TCP_HEX =
- // struct nlmsghdr
- "50000000" + // length = 80
- "0001" + // type = (1 << 8) | 0
- "0501" + // flags
- "01000000" + // seqno = 1
- "00000000" + // pid = 0
- // struct nfgenmsg
- "02" + // nfgen_family = AF_INET
- "00" + // version = NFNETLINK_V0
- "0000" + // res_id
- // struct nlattr
- "3400" + // nla_len = 52
- "0180" + // nla_type = nested CTA_TUPLE_ORIG
- // struct nlattr
- "1400" + // nla_len = 20
- "0180" + // nla_type = nested CTA_TUPLE_IP
- "0800 0100 C0A82BD1" + // nla_type=CTA_IP_V4_SRC, ip=192.168.43.209
- "0800 0200 17D30D1A" + // nla_type=CTA_IP_V4_DST, ip=23.211.13.26
- // struct nlattr
- "1C00" + // nla_len = 28
- "0280" + // nla_type = nested CTA_TUPLE_PROTO
- "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=6
- "0600 0200 AD2D 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=44333 (big endian)
- "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
- // struct nlattr
- "0800" + // nla_len = 8
- "0700" + // nla_type = CTA_TIMEOUT
- "00069780"; // nla_value = 432000 (big endian)
- public static final byte[] CT_V4UPDATE_TCP_BYTES =
- HexEncoding.decode(CT_V4UPDATE_TCP_HEX.replaceAll(" ", "").toCharArray(), false);
-
- // Example 2: UDP (100.96.167.146, 37069) -> (216.58.197.10, 443)
- public static final String CT_V4UPDATE_UDP_HEX =
- // struct nlmsghdr
- "50000000" + // length = 80
- "0001" + // type = (1 << 8) | 0
- "0501" + // flags
- "01000000" + // seqno = 1
- "00000000" + // pid = 0
- // struct nfgenmsg
- "02" + // nfgen_family = AF_INET
- "00" + // version = NFNETLINK_V0
- "0000" + // res_id
- // struct nlattr
- "3400" + // nla_len = 52
- "0180" + // nla_type = nested CTA_TUPLE_ORIG
- // struct nlattr
- "1400" + // nla_len = 20
- "0180" + // nla_type = nested CTA_TUPLE_IP
- "0800 0100 6460A792" + // nla_type=CTA_IP_V4_SRC, ip=100.96.167.146
- "0800 0200 D83AC50A" + // nla_type=CTA_IP_V4_DST, ip=216.58.197.10
- // struct nlattr
- "1C00" + // nla_len = 28
- "0280" + // nla_type = nested CTA_TUPLE_PROTO
- "0500 0100 11 000000" + // nla_type=CTA_PROTO_NUM, proto=17
- "0600 0200 90CD 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=37069 (big endian)
- "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
- // struct nlattr
- "0800" + // nla_len = 8
- "0700" + // nla_type = CTA_TIMEOUT
- "000000B4"; // nla_value = 180 (big endian)
- public static final byte[] CT_V4UPDATE_UDP_BYTES =
- HexEncoding.decode(CT_V4UPDATE_UDP_HEX.replaceAll(" ", "").toCharArray(), false);
-
- @Test
- public void testConntrackIPv4TcpTimeoutUpdate() throws Exception {
- assumeTrue(USING_LE);
-
- final byte[] tcp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
- OsConstants.IPPROTO_TCP,
- (Inet4Address) InetAddress.getByName("192.168.43.209"), 44333,
- (Inet4Address) InetAddress.getByName("23.211.13.26"), 443,
- 432000);
- assertArrayEquals(CT_V4UPDATE_TCP_BYTES, tcp);
- }
-
- @Test
- public void testConntrackIPv4UdpTimeoutUpdate() throws Exception {
- assumeTrue(USING_LE);
-
- final byte[] udp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
- OsConstants.IPPROTO_UDP,
- (Inet4Address) InetAddress.getByName("100.96.167.146"), 37069,
- (Inet4Address) InetAddress.getByName("216.58.197.10"), 443,
- 180);
- assertArrayEquals(CT_V4UPDATE_UDP_BYTES, udp);
- }
-}
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
deleted file mode 100644
index 84c5784..0000000
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2018 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.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_STREAM;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.netlink.StructNlMsgHdr;
-import android.os.Process;
-import android.system.Os;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InetDiagSocketTest {
- private final String TAG = "InetDiagSocketTest";
- private ConnectivityManager mCm;
- private Context mContext;
- private final static int SOCKET_TIMEOUT_MS = 100;
-
- @Before
- public void setUp() throws Exception {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- mContext = instrumentation.getTargetContext();
- mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- private class Connection {
- public int socketDomain;
- public int socketType;
- public InetAddress localAddress;
- public InetAddress remoteAddress;
- public InetAddress localhostAddress;
- public InetSocketAddress local;
- public InetSocketAddress remote;
- public int protocol;
- public FileDescriptor localFd;
- public FileDescriptor remoteFd;
-
- public FileDescriptor createSocket() throws Exception {
- return Os.socket(socketDomain, socketType, protocol);
- }
-
- public Connection(String to, String from) throws Exception {
- remoteAddress = InetAddress.getByName(to);
- if (from != null) {
- localAddress = InetAddress.getByName(from);
- } else {
- localAddress = (remoteAddress instanceof Inet4Address) ?
- Inet4Address.getByName("localhost") : Inet6Address.getByName("::");
- }
- if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) {
- socketDomain = AF_INET;
- localhostAddress = Inet4Address.getByName("localhost");
- } else {
- socketDomain = AF_INET6;
- localhostAddress = Inet6Address.getByName("::");
- }
- }
-
- public void close() throws Exception {
- Os.close(localFd);
- }
- }
-
- private class TcpConnection extends Connection {
- public TcpConnection(String to, String from) throws Exception {
- super(to, from);
- protocol = IPPROTO_TCP;
- socketType = SOCK_STREAM;
-
- remoteFd = createSocket();
- Os.bind(remoteFd, remoteAddress, 0);
- Os.listen(remoteFd, 10);
- int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort();
-
- localFd = createSocket();
- Os.bind(localFd, localAddress, 0);
- Os.connect(localFd, remoteAddress, remotePort);
-
- local = (InetSocketAddress) Os.getsockname(localFd);
- remote = (InetSocketAddress) Os.getpeername(localFd);
- }
-
- public void close() throws Exception {
- super.close();
- Os.close(remoteFd);
- }
- }
- private class UdpConnection extends Connection {
- public UdpConnection(String to, String from) throws Exception {
- super(to, from);
- protocol = IPPROTO_UDP;
- socketType = SOCK_DGRAM;
-
- remoteFd = null;
- localFd = createSocket();
- Os.bind(localFd, localAddress, 0);
-
- Os.connect(localFd, remoteAddress, 7);
- local = (InetSocketAddress) Os.getsockname(localFd);
- remote = new InetSocketAddress(remoteAddress, 7);
- }
- }
-
- private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
- InetSocketAddress remote, boolean expectSuccess) {
- final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);
-
- if (expectSuccess) {
- assertEquals(Process.myUid(), uid);
- } else {
- assertNotEquals(Process.myUid(), uid);
- }
- }
-
- private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
- UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(),
- conn.localAddress.getHostAddress());
- final int localPort = udp.local.getPort();
- udp.close();
- return localPort;
- }
-
- /**
- * Create a test connection for UDP and TCP sockets and verify that this
- * {protocol, local, remote} socket result in receiving a valid UID.
- */
- public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
- TcpConnection tcp = new TcpConnection(to, from);
- checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
- checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
- checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false);
- checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
- tcp.close();
-
- UdpConnection udp = new UdpConnection(to,from);
- checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
- checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
- checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
- udp.remote, false);
- udp.close();
- }
-
- @Test
- public void testGetConnectionOwnerUid() throws Exception {
- checkGetConnectionOwnerUid("::", null);
- checkGetConnectionOwnerUid("::", "::");
- checkGetConnectionOwnerUid("0.0.0.0", null);
- checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0");
- checkGetConnectionOwnerUid("127.0.0.1", null);
- checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2");
- checkGetConnectionOwnerUid("::1", null);
- checkGetConnectionOwnerUid("::1", "::1");
- }
-
- /* Verify fix for b/141603906 */
- @Test
- public void testB141603906() throws Exception {
- final InetSocketAddress src = new InetSocketAddress(0);
- final InetSocketAddress dst = new InetSocketAddress(0);
- final int numThreads = 8;
- final int numSockets = 5000;
- final Thread[] threads = new Thread[numThreads];
-
- for (int i = 0; i < numThreads; i++) {
- threads[i] = new Thread(() -> {
- for (int j = 0; j < numSockets; j++) {
- mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
- }
- });
- }
-
- for (Thread thread : threads) {
- thread.start();
- }
-
- for (Thread thread : threads) {
- thread.join();
- }
- }
-
- // Hexadecimal representation of InetDiagReqV2 request.
- private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
- // struct nlmsghdr
- "48000000" + // length = 72
- "1400" + // type = SOCK_DIAG_BY_FAMILY
- "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP
- "00000000" + // seqno
- "00000000" + // pid (0 == kernel)
- // struct inet_diag_req_v2
- "02" + // family = AF_INET
- "11" + // protcol = IPPROTO_UDP
- "00" + // idiag_ext
- "00" + // pad
- "ffffffff" + // idiag_states
- // inet_diag_sockid
- "a5de" + // idiag_sport = 42462
- "b971" + // idiag_dport = 47473
- "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2
- "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
- "00000000" + // idiag_if
- "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
- private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES =
- HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false);
-
- @Test
- public void testInetDiagReqV2UdpInet4() throws Exception {
- InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"),
- 42462);
- InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
- 47473);
- final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET,
- (short) (NLM_F_REQUEST | NLM_F_DUMP));
- assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg);
- }
-
- // Hexadecimal representation of InetDiagReqV2 request.
- private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX =
- // struct nlmsghdr
- "48000000" + // length = 72
- "1400" + // type = SOCK_DIAG_BY_FAMILY
- "0100" + // flags = NLM_F_REQUEST
- "00000000" + // seqno
- "00000000" + // pid (0 == kernel)
- // struct inet_diag_req_v2
- "0a" + // family = AF_INET6
- "06" + // protcol = IPPROTO_TCP
- "00" + // idiag_ext
- "00" + // pad
- "ffffffff" + // idiag_states
- // inet_diag_sockid
- "a5de" + // idiag_sport = 42462
- "b971" + // idiag_dport = 47473
- "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
- "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
- "00000000" + // idiag_if
- "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
- private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES =
- HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false);
-
- @Test
- public void testInetDiagReqV2TcpInet6() throws Exception {
- InetSocketAddress local = new InetSocketAddress(
- InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
- InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
- 47473);
- byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
- NLM_F_REQUEST);
-
- assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
- }
-
- // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO.
- private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX =
- // struct nlmsghdr
- "48000000" + // length = 72
- "1400" + // type = SOCK_DIAG_BY_FAMILY
- "0100" + // flags = NLM_F_REQUEST
- "00000000" + // seqno
- "00000000" + // pid (0 == kernel)
- // struct inet_diag_req_v2
- "02" + // family = AF_INET
- "06" + // protcol = IPPROTO_TCP
- "02" + // idiag_ext = INET_DIAG_INFO
- "00" + // pad
- "ffffffff" + // idiag_states
- // inet_diag_sockid
- "3039" + // idiag_sport = 12345
- "d431" + // idiag_dport = 54321
- "01020304000000000000000000000000" + // idiag_src = 1.2.3.4
- "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4
- "00000000" + // idiag_if
- "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
-
- private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES =
- HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false);
- private static final int TCP_ALL_STATES = 0xffffffff;
- @Test
- public void testInetDiagReqV2TcpInetWithExt() throws Exception {
- InetSocketAddress local = new InetSocketAddress(
- InetAddress.getByName("1.2.3.4"), 12345);
- InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
- 54321);
- byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET,
- NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES);
-
- assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg);
-
- local = new InetSocketAddress(
- InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
- remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
- 47473);
- msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
- NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-
- assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
- }
-
- // Hexadecimal representation of InetDiagReqV2 request with no socket specified.
- private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX =
- // struct nlmsghdr
- "48000000" + // length = 72
- "1400" + // type = SOCK_DIAG_BY_FAMILY
- "0100" + // flags = NLM_F_REQUEST
- "00000000" + // seqno
- "00000000" + // pid (0 == kernel)
- // struct inet_diag_req_v2
- "0a" + // family = AF_INET6
- "06" + // protcol = IPPROTO_TCP
- "00" + // idiag_ext
- "00" + // pad
- "ffffffff" + // idiag_states
- // inet_diag_sockid
- "0000" + // idiag_sport
- "0000" + // idiag_dport
- "00000000000000000000000000000000" + // idiag_src
- "00000000000000000000000000000000" + // idiag_dst
- "00000000" + // idiag_if
- "0000000000000000"; // idiag_cookie
-
- private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES =
- HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false);
-
- @Test
- public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception {
- InetSocketAddress local = new InetSocketAddress(
- InetAddress.getByName("fe80::fe6a:ed4b"), 12345);
- InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
- 54321);
- // Verify no socket specified if either local or remote socket address is null.
- byte[] msgExt = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
- NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
- byte[] msg;
- try {
- msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6,
- NLM_F_REQUEST);
- fail("Both remote and local should be null, expected UnknownHostException");
- } catch (NullPointerException e) {
- }
-
- try {
- msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6,
- NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
- fail("Both remote and local should be null, expected UnknownHostException");
- } catch (NullPointerException e) {
- }
-
- msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
- NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
- assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msg);
- assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt);
- }
-
- // Hexadecimal representation of InetDiagReqV2 request.
- private static final String INET_DIAG_MSG_HEX =
- // struct nlmsghdr
- "58000000" + // length = 88
- "1400" + // type = SOCK_DIAG_BY_FAMILY
- "0200" + // flags = NLM_F_MULTI
- "00000000" + // seqno
- "f5220000" + // pid (0 == kernel)
- // struct inet_diag_msg
- "0a" + // family = AF_INET6
- "01" + // idiag_state
- "00" + // idiag_timer
- "00" + // idiag_retrans
- // inet_diag_sockid
- "a817" + // idiag_sport = 43031
- "960f" + // idiag_dport = 38415
- "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
- "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
- "00000000" + // idiag_if
- "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
- "00000000" + // idiag_expires
- "00000000" + // idiag_rqueue
- "00000000" + // idiag_wqueue
- "a3270000" + // idiag_uid
- "A57E1900"; // idiag_inode
- private static final byte[] INET_DIAG_MSG_BYTES =
- HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
-
- @Test
- public void testParseInetDiagResponse() throws Exception {
- final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
- byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
- final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
- assertNotNull(msg);
-
- assertTrue(msg instanceof InetDiagMessage);
- final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
- assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
-
- final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
- assertNotNull(hdr);
- assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
- assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
- assertEquals(0, hdr.nlmsg_seq);
- assertEquals(8949, hdr.nlmsg_pid);
- }
-}
diff --git a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
deleted file mode 100644
index 44ab605..0000000
--- a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.StructNlMsgErr;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetlinkErrorMessageTest {
- private final String TAG = "NetlinkErrorMessageTest";
-
- // Hexadecimal representation of packet capture.
- public static final String NLM_ERROR_OK_HEX =
- // struct nlmsghdr
- "24000000" + // length = 36
- "0200" + // type = 2 (NLMSG_ERROR)
- "0000" + // flags
- "26350000" + // seqno
- "64100000" + // pid = userspace process
- // error integer
- "00000000" + // "errno" (0 == OK)
- // struct nlmsghdr
- "30000000" + // length (48) of original request
- "1C00" + // type = 28 (RTM_NEWNEIGH)
- "0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
- "26350000" + // seqno
- "00000000"; // pid = kernel
- public static final byte[] NLM_ERROR_OK =
- HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
-
- @Test
- public void testParseNlmErrorOk() {
- final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
- byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
- final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
- assertNotNull(msg);
- assertTrue(msg instanceof NetlinkErrorMessage);
- final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg;
-
- final StructNlMsgHdr hdr = errorMsg.getHeader();
- assertNotNull(hdr);
- assertEquals(36, hdr.nlmsg_len);
- assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type);
- assertEquals(0, hdr.nlmsg_flags);
- assertEquals(13606, hdr.nlmsg_seq);
- assertEquals(4196, hdr.nlmsg_pid);
-
- final StructNlMsgErr err = errorMsg.getNlMsgError();
- assertNotNull(err);
- assertEquals(0, err.error);
- assertNotNull(err.msg);
- assertEquals(48, err.msg.nlmsg_len);
- assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type);
- assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags);
- assertEquals(13606, err.msg.nlmsg_seq);
- assertEquals(0, err.msg.nlmsg_pid);
- }
-}
diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
deleted file mode 100644
index 3916578..0000000
--- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
-import static android.system.OsConstants.NETLINK_ROUTE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNlMsgHdr;
-import android.system.NetlinkSocketAddress;
-import android.system.Os;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.io.IoUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetlinkSocketTest {
- private final String TAG = "NetlinkSocketTest";
-
- @Test
- public void testBasicWorkingGetNeighborsQuery() throws Exception {
- final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE);
- assertNotNull(fd);
-
- NetlinkSocket.connectToKernel(fd);
-
- final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd);
- assertNotNull(localAddr);
- assertEquals(0, localAddr.getGroupsMask());
- assertTrue(0 != localAddr.getPortId());
-
- final int TEST_SEQNO = 5;
- final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
- assertNotNull(req);
-
- final long TIMEOUT = 500;
- assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT));
-
- int neighMessageCount = 0;
- int doneMessageCount = 0;
-
- while (doneMessageCount == 0) {
- ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT);
- assertNotNull(response);
- assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
- assertEquals(0, response.position());
- assertEquals(ByteOrder.nativeOrder(), response.order());
-
- // Verify the messages at least appears minimally reasonable.
- while (response.remaining() > 0) {
- final NetlinkMessage msg = NetlinkMessage.parse(response);
- assertNotNull(msg);
- final StructNlMsgHdr hdr = msg.getHeader();
- assertNotNull(hdr);
-
- if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
- doneMessageCount++;
- continue;
- }
-
- assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
- assertTrue(msg instanceof RtNetlinkNeighborMessage);
- assertTrue((hdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0);
- assertEquals(TEST_SEQNO, hdr.nlmsg_seq);
- assertEquals(localAddr.getPortId(), hdr.nlmsg_pid);
-
- neighMessageCount++;
- }
- }
-
- assertEquals(1, doneMessageCount);
- // TODO: make sure this test passes sanely in airplane mode.
- assertTrue(neighMessageCount > 0);
-
- IoUtils.closeQuietly(fd);
- }
-}
diff --git a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
deleted file mode 100644
index 8162522..0000000
--- a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2015 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.net.netlink;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNlMsgHdr;
-import android.system.OsConstants;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class RtNetlinkNeighborMessageTest {
- private final String TAG = "RtNetlinkNeighborMessageTest";
-
- // Hexadecimal representation of packet capture.
- public static final String RTM_DELNEIGH_HEX =
- // struct nlmsghdr
- "4c000000" + // length = 76
- "1d00" + // type = 29 (RTM_DELNEIGH)
- "0000" + // flags
- "00000000" + // seqno
- "00000000" + // pid (0 == kernel)
- // struct ndmsg
- "02" + // family
- "00" + // pad1
- "0000" + // pad2
- "15000000" + // interface index (21 == wlan0, on test device)
- "0400" + // NUD state (0x04 == NUD_STALE)
- "00" + // flags
- "01" + // type
- // struct nlattr: NDA_DST
- "0800" + // length = 8
- "0100" + // type (1 == NDA_DST, for neighbor messages)
- "c0a89ffe" + // IPv4 address (== 192.168.159.254)
- // struct nlattr: NDA_LLADDR
- "0a00" + // length = 10
- "0200" + // type (2 == NDA_LLADDR, for neighbor messages)
- "00005e000164" + // MAC Address (== 00:00:5e:00:01:64)
- "0000" + // padding, for 4 byte alignment
- // struct nlattr: NDA_PROBES
- "0800" + // length = 8
- "0400" + // type (4 == NDA_PROBES, for neighbor messages)
- "01000000" + // number of probes
- // struct nlattr: NDA_CACHEINFO
- "1400" + // length = 20
- "0300" + // type (3 == NDA_CACHEINFO, for neighbor messages)
- "05190000" + // ndm_used, as "clock ticks ago"
- "05190000" + // ndm_confirmed, as "clock ticks ago"
- "190d0000" + // ndm_updated, as "clock ticks ago"
- "00000000"; // ndm_refcnt
- public static final byte[] RTM_DELNEIGH =
- HexEncoding.decode(RTM_DELNEIGH_HEX.toCharArray(), false);
-
- // Hexadecimal representation of packet capture.
- public static final String RTM_NEWNEIGH_HEX =
- // struct nlmsghdr
- "58000000" + // length = 88
- "1c00" + // type = 28 (RTM_NEWNEIGH)
- "0000" + // flags
- "00000000" + // seqno
- "00000000" + // pid (0 == kernel)
- // struct ndmsg
- "0a" + // family
- "00" + // pad1
- "0000" + // pad2
- "15000000" + // interface index (21 == wlan0, on test device)
- "0400" + // NUD state (0x04 == NUD_STALE)
- "80" + // flags
- "01" + // type
- // struct nlattr: NDA_DST
- "1400" + // length = 20
- "0100" + // type (1 == NDA_DST, for neighbor messages)
- "fe8000000000000086c9b2fffe6aed4b" + // IPv6 address (== fe80::86c9:b2ff:fe6a:ed4b)
- // struct nlattr: NDA_LLADDR
- "0a00" + // length = 10
- "0200" + // type (2 == NDA_LLADDR, for neighbor messages)
- "84c9b26aed4b" + // MAC Address (== 84:c9:b2:6a:ed:4b)
- "0000" + // padding, for 4 byte alignment
- // struct nlattr: NDA_PROBES
- "0800" + // length = 8
- "0400" + // type (4 == NDA_PROBES, for neighbor messages)
- "01000000" + // number of probes
- // struct nlattr: NDA_CACHEINFO
- "1400" + // length = 20
- "0300" + // type (3 == NDA_CACHEINFO, for neighbor messages)
- "eb0e0000" + // ndm_used, as "clock ticks ago"
- "861f0000" + // ndm_confirmed, as "clock ticks ago"
- "00000000" + // ndm_updated, as "clock ticks ago"
- "05000000"; // ndm_refcnt
- public static final byte[] RTM_NEWNEIGH =
- HexEncoding.decode(RTM_NEWNEIGH_HEX.toCharArray(), false);
-
- // An example of the full response from an RTM_GETNEIGH query.
- private static final String RTM_GETNEIGH_RESPONSE_HEX =
- // <-- struct nlmsghr -->|<-- struct ndmsg -->|<-- struct nlattr: NDA_DST -->|<-- NDA_LLADDR -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO -->|
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000001 0a00 0200 333300000001 0000 0800 0400 00000000 1400 0300 a2280000 32110000 32110000 01000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff000001 0a00 0200 3333ff000001 0000 0800 0400 00000000 1400 0300 0d280000 9d100000 9d100000 00000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0400 80 01 1400 0100 20010db800040ca00000000000000001 0a00 0200 84c9b26aed4b 0000 0800 0400 04000000 1400 0300 90100000 90100000 90080000 01000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff47da19 0a00 0200 3333ff47da19 0000 0800 0400 00000000 1400 0300 a1280000 31110000 31110000 01000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 912a0000 21130000 21130000 00000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 922a0000 22130000 22130000 00000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff5c2a83 0a00 0200 3333ff5c2a83 0000 0800 0400 00000000 1400 0300 391c0000 c9040000 c9040000 01000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 01000000 4000 00 02 1400 0100 00000000000000000000000000000000 0a00 0200 000000000000 0000 0800 0400 00000000 1400 0300 cd180200 5d010200 5d010200 08000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 352a0000 c5120000 c5120000 00000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 982a0000 28130000 28130000 00000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0800 80 01 1400 0100 fe8000000000000086c9b2fffe6aed4b 0a00 0200 84c9b26aed4b 0000 0800 0400 00000000 1400 0300 23000000 24000000 57000000 13000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 992a0000 29130000 29130000 01000000" +
- "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 2e2a0000 be120000 be120000 00000000" +
- "44000000 1c00 0200 00000000 3e2b0000 02 00 0000 18000000 4000 00 03 0800 0100 00000000 0400 0200 0800 0400 00000000 1400 0300 75280000 05110000 05110000 22000000";
- public static final byte[] RTM_GETNEIGH_RESPONSE =
- HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
-
- @Test
- public void testParseRtmDelNeigh() {
- final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
- byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
- final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
- assertNotNull(msg);
- assertTrue(msg instanceof RtNetlinkNeighborMessage);
- final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
- final StructNlMsgHdr hdr = neighMsg.getHeader();
- assertNotNull(hdr);
- assertEquals(76, hdr.nlmsg_len);
- assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type);
- assertEquals(0, hdr.nlmsg_flags);
- assertEquals(0, hdr.nlmsg_seq);
- assertEquals(0, hdr.nlmsg_pid);
-
- final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
- assertNotNull(ndmsgHdr);
- assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family);
- assertEquals(21, ndmsgHdr.ndm_ifindex);
- assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
- final InetAddress destination = neighMsg.getDestination();
- assertNotNull(destination);
- assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
- }
-
- @Test
- public void testParseRtmNewNeigh() {
- final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
- byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
- final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
- assertNotNull(msg);
- assertTrue(msg instanceof RtNetlinkNeighborMessage);
- final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
- final StructNlMsgHdr hdr = neighMsg.getHeader();
- assertNotNull(hdr);
- assertEquals(88, hdr.nlmsg_len);
- assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
- assertEquals(0, hdr.nlmsg_flags);
- assertEquals(0, hdr.nlmsg_seq);
- assertEquals(0, hdr.nlmsg_pid);
-
- final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
- assertNotNull(ndmsgHdr);
- assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family);
- assertEquals(21, ndmsgHdr.ndm_ifindex);
- assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
- final InetAddress destination = neighMsg.getDestination();
- assertNotNull(destination);
- assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
- }
-
- @Test
- public void testParseRtmGetNeighResponse() {
- final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
- byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
-
- int messageCount = 0;
- while (byteBuffer.remaining() > 0) {
- final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
- assertNotNull(msg);
- assertTrue(msg instanceof RtNetlinkNeighborMessage);
- final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
- final StructNlMsgHdr hdr = neighMsg.getHeader();
- assertNotNull(hdr);
- assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
- assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
- assertEquals(0, hdr.nlmsg_seq);
- assertEquals(11070, hdr.nlmsg_pid);
-
- messageCount++;
- }
- // TODO: add more detailed spot checks.
- assertEquals(14, messageCount);
- }
-
- @Test
- public void testCreateRtmNewNeighMessage() {
- final int seqNo = 2635;
- final int ifIndex = 14;
- final byte[] llAddr =
- new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
-
- // Hexadecimal representation of our created packet.
- final String expectedNewNeighHex =
- // struct nlmsghdr
- "30000000" + // length = 48
- "1c00" + // type = 28 (RTM_NEWNEIGH)
- "0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
- "4b0a0000" + // seqno
- "00000000" + // pid (0 == kernel)
- // struct ndmsg
- "02" + // family
- "00" + // pad1
- "0000" + // pad2
- "0e000000" + // interface index (14)
- "0800" + // NUD state (0x08 == NUD_DELAY)
- "00" + // flags
- "00" + // type
- // struct nlattr: NDA_DST
- "0800" + // length = 8
- "0100" + // type (1 == NDA_DST, for neighbor messages)
- "7f000001" + // IPv4 address (== 127.0.0.1)
- // struct nlattr: NDA_LLADDR
- "0a00" + // length = 10
- "0200" + // type (2 == NDA_LLADDR, for neighbor messages)
- "010203040506" + // MAC Address (== 01:02:03:04:05:06)
- "0000"; // padding, for 4 byte alignment
- final byte[] expectedNewNeigh =
- HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
-
- final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
- seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
- if (!Arrays.equals(expectedNewNeigh, bytes)) {
- assertEquals(expectedNewNeigh.length, bytes.length);
- for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
- assertEquals(expectedNewNeigh[i], bytes[i]);
- }
- }
- }
-}
diff --git a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
deleted file mode 100644
index 35f8c79..0000000
--- a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
-import static android.net.shared.Inet4AddressUtils.getImplicitNetmask;
-import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTL;
-import static android.net.shared.Inet4AddressUtils.netmaskToPrefixLength;
-import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
-import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.fail;
-
-import android.net.InetAddresses;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class Inet4AddressUtilsTest {
-
- @Test
- public void testInet4AddressToIntHTL() {
- assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0")));
- assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0")));
- assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0")));
- assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0")));
- assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254")));
- assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255")));
- }
-
- @Test
- public void testIntToInet4AddressHTL() {
- assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0));
- assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
- assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
- assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
- assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
- assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
- }
-
- @Test
- public void testInet4AddressToIntHTH() {
- assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0")));
- assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0")));
- assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0")));
- assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0")));
- assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254")));
- assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255")));
- }
-
- @Test
- public void testIntToInet4AddressHTH() {
- assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0));
- assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
- assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
- assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
- assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
- assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
- }
-
-
- @Test
- public void testPrefixLengthToV4NetmaskIntHTL() {
- assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
- assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
- assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
- assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
- assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
- assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
- }
-
- @Test
- public void testPrefixLengthToV4NetmaskIntHTH() {
- assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
- assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
- assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
- assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
- assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
- assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
- prefixLengthToV4NetmaskIntHTH(-1);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
- prefixLengthToV4NetmaskIntHTH(33);
- }
-
- private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
- final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
- final int addrInt = inet4AddressToIntHTH(ipv4Address(addr));
- assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
- }
-
- @Test
- public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
- checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
- checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
- checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
- checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
- }
-
- @Test
- public void testGetImplicitNetmask() {
- assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2")));
- assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7")));
- assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105")));
- assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145")));
- assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1")));
- assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1")));
- assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1")));
- assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8")));
- }
-
- private void assertInvalidNetworkMask(Inet4Address addr) {
- try {
- netmaskToPrefixLength(addr);
- fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testNetmaskToPrefixLength() {
- assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0")));
- assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0")));
- assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0")));
- assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0")));
- assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254")));
- assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255")));
-
- assertInvalidNetworkMask(ipv4Address("0.0.0.1"));
- assertInvalidNetworkMask(ipv4Address("255.255.255.253"));
- assertInvalidNetworkMask(ipv4Address("255.255.0.255"));
- }
-
- @Test
- public void testGetPrefixMaskAsAddress() {
- assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
- assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
- assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
- assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
- }
-
- @Test
- public void testGetBroadcastAddress() {
- assertEquals("192.168.15.255",
- getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress());
- assertEquals("192.255.255.255",
- getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress());
- assertEquals("192.168.0.123",
- getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress());
- assertEquals("255.255.255.255",
- getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress());
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetBroadcastAddress_PrefixTooLarge() {
- getBroadcastAddress(ipv4Address("192.168.0.123"), 33);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetBroadcastAddress_NegativePrefix() {
- getBroadcastAddress(ipv4Address("192.168.0.123"), -1);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
- getPrefixMaskAsInet4Address(33);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetPrefixMaskAsAddress_NegativePrefix() {
- getPrefixMaskAsInet4Address(-1);
- }
-
- private Inet4Address ipv4Address(String addr) {
- return (Inet4Address) InetAddresses.parseNumericAddress(addr);
- }
-}
diff --git a/tests/net/java/android/net/shared/InitialConfigurationTest.java b/tests/net/java/android/net/shared/InitialConfigurationTest.java
deleted file mode 100644
index 17f8324..0000000
--- a/tests/net/java/android/net/shared/InitialConfigurationTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import static android.net.InetAddresses.parseNumericAddress;
-
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.function.Consumer;
-
-/**
- * Tests for {@link InitialConfiguration}
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InitialConfigurationTest {
- private InitialConfiguration mConfig;
-
- @Before
- public void setUp() {
- mConfig = new InitialConfiguration();
- mConfig.ipAddresses.addAll(Arrays.asList(
- new LinkAddress(parseNumericAddress("192.168.45.45"), 16),
- new LinkAddress(parseNumericAddress("2001:db8::45"), 33)));
- mConfig.directlyConnectedRoutes.addAll(Arrays.asList(
- new IpPrefix(parseNumericAddress("192.168.46.46"), 17),
- new IpPrefix(parseNumericAddress("2001:db8::46"), 34)));
- mConfig.dnsServers.addAll(Arrays.asList(
- parseNumericAddress("192.168.47.47"),
- parseNumericAddress("2001:db8::47")));
- // Any added InitialConfiguration field must be included in equals() to be tested properly
- assertFieldCountEquals(3, InitialConfiguration.class);
- }
-
- @Test
- public void testParcelUnparcelInitialConfiguration() {
- final InitialConfiguration unparceled =
- InitialConfiguration.fromStableParcelable(mConfig.toStableParcelable());
- assertEquals(mConfig, unparceled);
- }
-
- @Test
- public void testEquals() {
- assertEquals(mConfig, InitialConfiguration.copy(mConfig));
-
- assertNotEqualsAfterChange(c -> c.ipAddresses.add(
- new LinkAddress(parseNumericAddress("192.168.47.47"), 24)));
- assertNotEqualsAfterChange(c -> c.directlyConnectedRoutes.add(
- new IpPrefix(parseNumericAddress("192.168.46.46"), 32)));
- assertNotEqualsAfterChange(c -> c.dnsServers.add(parseNumericAddress("2001:db8::49")));
- assertFieldCountEquals(3, InitialConfiguration.class);
- }
-
- private void assertNotEqualsAfterChange(Consumer<InitialConfiguration> mutator) {
- final InitialConfiguration newConfig = InitialConfiguration.copy(mConfig);
- mutator.accept(newConfig);
- assertNotEquals(mConfig, newConfig);
- }
-}
diff --git a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
deleted file mode 100644
index f987389..0000000
--- a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable;
-import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
-
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.DhcpResults;
-import android.net.LinkAddress;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-
-/**
- * Tests for {@link IpConfigurationParcelableUtil}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConfigurationParcelableUtilTest {
- private DhcpResults mDhcpResults;
-
- @Before
- public void setUp() {
- mDhcpResults = new DhcpResults();
- mDhcpResults.ipAddress = new LinkAddress(parseNumericAddress("2001:db8::42"), 64);
- mDhcpResults.gateway = parseNumericAddress("192.168.42.42");
- mDhcpResults.dnsServers.add(parseNumericAddress("2001:db8::43"));
- mDhcpResults.dnsServers.add(parseNumericAddress("192.168.43.43"));
- mDhcpResults.domains = "example.com";
- mDhcpResults.serverAddress = (Inet4Address) parseNumericAddress("192.168.44.44");
- mDhcpResults.vendorInfo = "TEST_VENDOR_INFO";
- mDhcpResults.leaseDuration = 3600;
- mDhcpResults.serverHostName = "dhcp.example.com";
- mDhcpResults.mtu = 1450;
- // Any added DhcpResults field must be included in equals() to be tested properly
- assertFieldCountEquals(9, DhcpResults.class);
- }
-
- @Test
- public void testParcelUnparcelDhcpResults() {
- doDhcpResultsParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcelDhcpResults_NullIpAddress() {
- mDhcpResults.ipAddress = null;
- doDhcpResultsParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcelDhcpResults_NullGateway() {
- mDhcpResults.gateway = null;
- doDhcpResultsParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcelDhcpResults_NullDomains() {
- mDhcpResults.domains = null;
- doDhcpResultsParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcelDhcpResults_EmptyDomains() {
- mDhcpResults.domains = "";
- doDhcpResultsParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcelDhcpResults_NullServerAddress() {
- mDhcpResults.serverAddress = null;
- doDhcpResultsParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcelDhcpResults_NullVendorInfo() {
- mDhcpResults.vendorInfo = null;
- doDhcpResultsParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcelDhcpResults_NullServerHostName() {
- mDhcpResults.serverHostName = null;
- doDhcpResultsParcelUnparcelTest();
- }
-
- private void doDhcpResultsParcelUnparcelTest() {
- final DhcpResults unparceled = fromStableParcelable(toStableParcelable(mDhcpResults));
- assertEquals(mDhcpResults, unparceled);
- }
-}
diff --git a/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java b/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java
deleted file mode 100644
index 7079a28..0000000
--- a/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.shared;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.shared.ProvisioningConfiguration.fromStableParcelable;
-
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.StaticIpConfiguration;
-import android.net.apf.ApfCapabilities;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.function.Consumer;
-
-/**
- * Tests for {@link ProvisioningConfiguration}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ProvisioningConfigurationTest {
- private ProvisioningConfiguration mConfig;
-
- @Before
- public void setUp() {
- mConfig = new ProvisioningConfiguration();
- mConfig.mEnableIPv4 = true;
- mConfig.mEnableIPv6 = true;
- mConfig.mUsingMultinetworkPolicyTracker = true;
- mConfig.mUsingIpReachabilityMonitor = true;
- mConfig.mRequestedPreDhcpActionMs = 42;
- mConfig.mInitialConfig = new InitialConfiguration();
- mConfig.mInitialConfig.ipAddresses.add(
- new LinkAddress(parseNumericAddress("192.168.42.42"), 24));
- mConfig.mStaticIpConfig = new StaticIpConfiguration();
- mConfig.mStaticIpConfig.ipAddress =
- new LinkAddress(parseNumericAddress("2001:db8::42"), 90);
- // Not testing other InitialConfig or StaticIpConfig members: they have their own unit tests
- mConfig.mApfCapabilities = new ApfCapabilities(1, 2, 3);
- mConfig.mProvisioningTimeoutMs = 4200;
- mConfig.mIPv6AddrGenMode = 123;
- mConfig.mNetwork = new Network(321);
- mConfig.mDisplayName = "test_config";
- // Any added field must be included in equals() to be tested properly
- assertFieldCountEquals(12, ProvisioningConfiguration.class);
- }
-
- @Test
- public void testParcelUnparcel() {
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullInitialConfiguration() {
- mConfig.mInitialConfig = null;
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullStaticConfiguration() {
- mConfig.mStaticIpConfig = null;
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullApfCapabilities() {
- mConfig.mApfCapabilities = null;
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullNetwork() {
- mConfig.mNetwork = null;
- doParcelUnparcelTest();
- }
-
- private void doParcelUnparcelTest() {
- final ProvisioningConfiguration unparceled =
- fromStableParcelable(mConfig.toStableParcelable());
- assertEquals(mConfig, unparceled);
- }
-
- @Test
- public void testEquals() {
- assertEquals(mConfig, new ProvisioningConfiguration(mConfig));
-
- assertNotEqualsAfterChange(c -> c.mEnableIPv4 = false);
- assertNotEqualsAfterChange(c -> c.mEnableIPv6 = false);
- assertNotEqualsAfterChange(c -> c.mUsingMultinetworkPolicyTracker = false);
- assertNotEqualsAfterChange(c -> c.mUsingIpReachabilityMonitor = false);
- assertNotEqualsAfterChange(c -> c.mRequestedPreDhcpActionMs++);
- assertNotEqualsAfterChange(c -> c.mInitialConfig.ipAddresses.add(
- new LinkAddress(parseNumericAddress("192.168.47.47"), 16)));
- assertNotEqualsAfterChange(c -> c.mInitialConfig = null);
- assertNotEqualsAfterChange(c -> c.mStaticIpConfig.ipAddress =
- new LinkAddress(parseNumericAddress("2001:db8::47"), 64));
- assertNotEqualsAfterChange(c -> c.mStaticIpConfig = null);
- assertNotEqualsAfterChange(c -> c.mApfCapabilities = new ApfCapabilities(4, 5, 6));
- assertNotEqualsAfterChange(c -> c.mApfCapabilities = null);
- assertNotEqualsAfterChange(c -> c.mProvisioningTimeoutMs++);
- assertNotEqualsAfterChange(c -> c.mIPv6AddrGenMode++);
- assertNotEqualsAfterChange(c -> c.mNetwork = new Network(123));
- assertNotEqualsAfterChange(c -> c.mNetwork = null);
- assertNotEqualsAfterChange(c -> c.mDisplayName = "other_test");
- assertNotEqualsAfterChange(c -> c.mDisplayName = null);
- assertFieldCountEquals(12, ProvisioningConfiguration.class);
- }
-
- private void assertNotEqualsAfterChange(Consumer<ProvisioningConfiguration> mutator) {
- final ProvisioningConfiguration newConfig = new ProvisioningConfiguration(mConfig);
- mutator.accept(newConfig);
- assertNotEquals(mConfig, newConfig);
- }
-}
diff --git a/tests/net/java/android/net/util/InterfaceParamsTest.java b/tests/net/java/android/net/util/InterfaceParamsTest.java
deleted file mode 100644
index 141455c..0000000
--- a/tests/net/java/android/net/util/InterfaceParamsTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.net.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InterfaceParamsTest {
- @Test
- public void testNullInterfaceReturnsNull() {
- assertNull(InterfaceParams.getByName(null));
- }
-
- @Test
- public void testNonExistentInterfaceReturnsNull() {
- assertNull(InterfaceParams.getByName("doesnotexist0"));
- }
-
- @Test
- public void testLoopback() {
- final InterfaceParams ifParams = InterfaceParams.getByName("lo");
- assertNotNull(ifParams);
- assertEquals("lo", ifParams.name);
- assertTrue(ifParams.index > 0);
- assertNotNull(ifParams.macAddr);
- assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU);
- }
-}
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
deleted file mode 100644
index e1dba36..0000000
--- a/tests/net/java/android/net/util/SharedLogTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.net.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class SharedLogTest {
- private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
- private static final String TIMESTAMP = "HH:MM:SS";
-
- @Test
- public void testBasicOperation() {
- final SharedLog logTop = new SharedLog("top");
- logTop.mark("first post!");
-
- final SharedLog logLevel2a = logTop.forSubComponent("twoA");
- final SharedLog logLevel2b = logTop.forSubComponent("twoB");
- logLevel2b.e("2b or not 2b");
- logLevel2b.e("No exception", null);
- logLevel2b.e("Wait, here's one", new Exception("Test"));
- logLevel2a.w("second post?");
-
- final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
- logTop.log("still logging");
- logLevel3.log("3 >> 2");
- logLevel2a.mark("ok: last post");
-
- final String[] expected = {
- " - MARK first post!",
- " - [twoB] ERROR 2b or not 2b",
- " - [twoB] ERROR No exception",
- // No stacktrace in shared log, only in logcat
- " - [twoB] ERROR Wait, here's one: Test",
- " - [twoA] WARN second post?",
- " - still logging",
- " - [twoA.three] 3 >> 2",
- " - [twoA] MARK ok: last post",
- };
- // Verify the logs are all there and in the correct order.
- verifyLogLines(expected, logTop);
-
- // In fact, because they all share the same underlying LocalLog,
- // every subcomponent SharedLog's dump() is identical.
- verifyLogLines(expected, logLevel2a);
- verifyLogLines(expected, logLevel2b);
- verifyLogLines(expected, logLevel3);
- }
-
- private static void verifyLogLines(String[] expected, SharedLog log) {
- final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
- final PrintWriter pw = new PrintWriter(ostream, true);
- log.dump(null, pw, null);
-
- final String dumpOutput = ostream.toString();
- assertTrue(dumpOutput != null);
- assertTrue(!"".equals(dumpOutput));
-
- final String[] lines = dumpOutput.split("\n");
- assertEquals(expected.length, lines.length);
-
- for (int i = 0; i < expected.length; i++) {
- String got = lines[i];
- String want = expected[i];
- assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want));
- assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP),
- got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP));
- }
- }
-}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1d2e6b0..7ea9bcf 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,6 +23,9 @@
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
@@ -31,6 +34,7 @@
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
@@ -148,6 +152,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
+import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
@@ -247,6 +252,7 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Predicate;
import kotlin.reflect.KClass;
@@ -333,6 +339,9 @@
private class MockContext extends BroadcastInterceptingContext {
private final MockContentResolver mContentResolver;
+ // Contains all registered receivers since this object was created. Useful to clear
+ // them when needed, as BroadcastInterceptingContext does not provide this facility.
+ private final List<BroadcastReceiver> mRegisteredReceivers = new ArrayList<>();
@Spy private Resources mResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
@@ -346,6 +355,7 @@
"wifi,1,1,1,-1,true",
"mobile,0,0,0,-1,true",
"mobile_mms,2,0,2,60000,true",
+ "mobile_supl,3,0,2,60000,true",
});
when(mResources.getStringArray(
@@ -413,6 +423,19 @@
// make sure the code does not rely on unexpected permissions.
super.enforceCallingOrSelfPermission(permission, message);
}
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ mRegisteredReceivers.add(receiver);
+ return super.registerReceiver(receiver, filter);
+ }
+
+ public void clearRegisteredReceivers() {
+ // super.unregisterReceiver is a no-op for receivers that are not registered (because
+ // they haven't been registered or because they have already been unregistered).
+ // For the same reason, don't bother clearing mRegisteredReceivers.
+ for (final BroadcastReceiver rcv : mRegisteredReceivers) unregisterReceiver(rcv);
+ }
}
private void waitForIdle() {
@@ -441,7 +464,7 @@
}
// Bring up a network that we can use to send messages to ConnectivityService.
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
@@ -461,7 +484,7 @@
@Ignore
public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
// Bring up a network that we can use to send messages to ConnectivityService.
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
@@ -1230,17 +1253,26 @@
* Return a ConditionVariable that opens when {@code count} numbers of CONNECTIVITY_ACTION
* broadcasts are received.
*/
- private ConditionVariable waitForConnectivityBroadcasts(final int count) {
+ private ConditionVariable registerConnectivityBroadcast(final int count) {
+ return registerConnectivityBroadcastThat(count, intent -> true);
+ }
+
+ private ConditionVariable registerConnectivityBroadcastThat(final int count,
+ @NonNull final Predicate<Intent> filter) {
final ConditionVariable cv = new ConditionVariable();
- mServiceContext.registerReceiver(new BroadcastReceiver() {
+ final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
+ intentFilter.addAction(CONNECTIVITY_ACTION_SUPL);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
private int remaining = count;
public void onReceive(Context context, Intent intent) {
+ if (!filter.test(intent)) return;
if (--remaining == 0) {
cv.open();
mServiceContext.unregisterReceiver(this);
}
}
- }, new IntentFilter(CONNECTIVITY_ACTION));
+ };
+ mServiceContext.registerReceiver(receiver, intentFilter);
return cv;
}
@@ -1261,6 +1293,75 @@
}
@Test
+ public void testNetworkFeature() throws Exception {
+ // Connect the cell agent and wait for the connected broadcast.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL);
+ final ConditionVariable cv1 = registerConnectivityBroadcastThat(1,
+ intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE);
+ mCellNetworkAgent.connect(true);
+ waitFor(cv1);
+
+ // Build legacy request for SUPL.
+ final NetworkCapabilities legacyCaps = new NetworkCapabilities();
+ legacyCaps.addTransportType(TRANSPORT_CELLULAR);
+ legacyCaps.addCapability(NET_CAPABILITY_SUPL);
+ final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL,
+ ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
+
+ // Send request and check that the legacy broadcast for SUPL is sent correctly.
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ final ConditionVariable cv2 = registerConnectivityBroadcastThat(1,
+ intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
+ mCm.requestNetwork(legacyRequest, callback);
+ callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+ waitFor(cv2);
+
+ // File another request, withdraw it and make sure no broadcast is sent
+ final ConditionVariable cv3 = registerConnectivityBroadcast(1);
+ final TestNetworkCallback callback2 = new TestNetworkCallback();
+ mCm.requestNetwork(legacyRequest, callback2);
+ callback2.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+ mCm.unregisterNetworkCallback(callback2);
+ assertFalse(cv3.block(800)); // 800ms long enough to at least flake if this is sent
+ // As the broadcast did not fire, the receiver was not unregistered. Do this now.
+ mServiceContext.clearRegisteredReceivers();
+
+ // Withdraw the request and check that the broadcast for disconnection is sent.
+ final ConditionVariable cv4 = registerConnectivityBroadcastThat(1, intent ->
+ !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected()
+ && intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
+ mCm.unregisterNetworkCallback(callback);
+ waitFor(cv4);
+
+ // Re-file the request and expect the connected broadcast again
+ final ConditionVariable cv5 = registerConnectivityBroadcastThat(1,
+ intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
+ final TestNetworkCallback callback3 = new TestNetworkCallback();
+ mCm.requestNetwork(legacyRequest, callback3);
+ callback3.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+ waitFor(cv5);
+
+ // Disconnect the network and expect two disconnected broadcasts, one for SUPL and one
+ // for mobile. Use a small hack to check that both have been sent, but the order is
+ // not contractual.
+ final AtomicBoolean vanillaAction = new AtomicBoolean(false);
+ final AtomicBoolean suplAction = new AtomicBoolean(false);
+ final ConditionVariable cv6 = registerConnectivityBroadcastThat(2, intent -> {
+ if (intent.getAction().equals(CONNECTIVITY_ACTION)) {
+ vanillaAction.set(true);
+ } else if (intent.getAction().equals(CONNECTIVITY_ACTION_SUPL)) {
+ suplAction.set(true);
+ }
+ return !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected();
+ });
+ mCellNetworkAgent.disconnect();
+ waitFor(cv6);
+ assertTrue(vanillaAction.get());
+ assertTrue(suplAction.get());
+ }
+
+ @Test
public void testLingering() throws Exception {
verifyNoNetwork();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -1268,7 +1369,7 @@
assertNull(mCm.getActiveNetworkInfo());
assertNull(mCm.getActiveNetwork());
// Test bringing up validated cellular.
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
@@ -1278,7 +1379,7 @@
assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
// Test bringing up validated WiFi.
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1295,7 +1396,7 @@
assertLength(1, mCm.getAllNetworks());
assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
// Test WiFi disconnect.
- cv = waitForConnectivityBroadcasts(1);
+ cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.disconnect();
waitFor(cv);
verifyNoNetwork();
@@ -1305,7 +1406,7 @@
public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
// Test bringing up unvalidated WiFi
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1320,17 +1421,17 @@
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up validated cellular
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test cellular disconnect.
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mCellNetworkAgent.disconnect();
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test WiFi disconnect.
- cv = waitForConnectivityBroadcasts(1);
+ cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.disconnect();
waitFor(cv);
verifyNoNetwork();
@@ -1340,23 +1441,23 @@
public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
// Test bringing up unvalidated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test WiFi disconnect.
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.disconnect();
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test cellular disconnect.
- cv = waitForConnectivityBroadcasts(1);
+ cv = registerConnectivityBroadcast(1);
mCellNetworkAgent.disconnect();
waitFor(cv);
verifyNoNetwork();
@@ -1366,7 +1467,7 @@
public void testUnlingeringDoesNotValidate() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1374,14 +1475,14 @@
NET_CAPABILITY_VALIDATED));
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
// Test cellular disconnect.
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mCellNetworkAgent.disconnect();
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1394,23 +1495,23 @@
public void testCellularOutscoresWeakWifi() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test WiFi getting really weak.
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.adjustScore(-11);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test WiFi restoring signal strength.
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.adjustScore(11);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1430,7 +1531,7 @@
mCellNetworkAgent.expectDisconnected();
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ final ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1449,18 +1550,18 @@
public void testCellularFallback() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Reevaluate WiFi (it'll instantly fail DNS).
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
@@ -1470,7 +1571,7 @@
NET_CAPABILITY_VALIDATED));
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Reevaluate cellular (it'll instantly fail DNS).
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
@@ -1487,18 +1588,18 @@
public void testWiFiFallback() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Reevaluate cellular (it'll instantly fail DNS).
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
@@ -1573,7 +1674,7 @@
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
// Test unvalidated networks
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -1588,7 +1689,7 @@
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1597,7 +1698,7 @@
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- cv = waitForConnectivityBroadcasts(2);
+ cv = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -1605,7 +1706,7 @@
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- cv = waitForConnectivityBroadcasts(1);
+ cv = registerConnectivityBroadcast(1);
mCellNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -2203,7 +2304,7 @@
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ final ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -2231,7 +2332,7 @@
public void testMMSonCell() throws Exception {
// Test bringing up cellular without MMS
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
@@ -3692,7 +3793,7 @@
}
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -4225,7 +4326,7 @@
assertNotPinnedToWifi();
// Disconnect cell and wifi.
- ConditionVariable cv = waitForConnectivityBroadcasts(3); // cell down, wifi up, wifi down.
+ ConditionVariable cv = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down.
mCellNetworkAgent.disconnect();
mWiFiNetworkAgent.disconnect();
waitFor(cv);
@@ -4238,7 +4339,7 @@
assertPinnedToWifiWithWifiDefault();
// ... and is maintained even when that network is no longer the default.
- cv = waitForConnectivityBroadcasts(1);
+ cv = registerConnectivityBroadcast(1);
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mCellNetworkAgent.connect(true);
waitFor(cv);
@@ -4339,7 +4440,7 @@
@Test
public void testNetworkInfoOfTypeNone() throws Exception {
- ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
+ ConditionVariable broadcastCV = registerConnectivityBroadcast(1);
verifyNoNetwork();
TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
@@ -5791,7 +5892,7 @@
.destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
// Disconnect wifi
- ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ ConditionVariable cv = registerConnectivityBroadcast(1);
reset(mNetworkManagementService);
mWiFiNetworkAgent.disconnect();
waitFor(cv);
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
index f045369..42d4cf3 100644
--- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -18,6 +18,7 @@
import android.net.ConnectivityManager.TYPE_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.ConnectivityManager.TYPE_WIMAX
import android.net.NetworkInfo.DetailedState.CONNECTED
@@ -46,7 +47,7 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
class LegacyTypeTrackerTest {
- private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET)
+ private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
private val mMockService = mock(ConnectivityService::class.java).apply {
doReturn(false).`when`(this).isDefaultNetwork(any())
@@ -70,6 +71,26 @@
}
@Test
+ fun testSupl() {
+ val mobileNai = mock(NetworkAgentInfo::class.java)
+ mTracker.add(TYPE_MOBILE, mobileNai)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
+ reset(mMockService)
+ mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
+ reset(mMockService)
+ mTracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
+ reset(mMockService)
+ mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
+ reset(mMockService)
+ mTracker.remove(mobileNai, false)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
+ }
+
+ @Test
fun testAddNetwork() {
val mobileNai = mock(NetworkAgentInfo::class.java)
val wifiNai = mock(NetworkAgentInfo::class.java)
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 9580763..d57f225 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -40,6 +41,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import org.junit.Before;
@@ -60,12 +62,19 @@
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
+ static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
static {
CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+
+ // Set the underyling network to wifi.
+ VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
+ VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
}
@Mock Context mCtx;
@@ -75,6 +84,7 @@
@Mock NotificationManager mNotificationManager;
@Mock NetworkAgentInfo mWifiNai;
@Mock NetworkAgentInfo mCellNai;
+ @Mock NetworkAgentInfo mVpnNai;
@Mock NetworkInfo mNetworkInfo;
ArgumentCaptor<Notification> mCaptor;
@@ -88,6 +98,9 @@
mWifiNai.networkInfo = mNetworkInfo;
mCellNai.networkCapabilities = CELL_CAPABILITIES;
mCellNai.networkInfo = mNetworkInfo;
+ mVpnNai.networkCapabilities = VPN_CAPABILITIES;
+ mVpnNai.networkInfo = mNetworkInfo;
+ doReturn(true).when(mVpnNai).isVPN();
when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm);
when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
@@ -97,6 +110,35 @@
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
}
+ private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
+ final String tag = NetworkNotificationManager.tagFor(id);
+ mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
+ verify(mNotificationManager, times(1))
+ .notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any());
+ final int transportType = NetworkNotificationManager.approximateTransportType(nai);
+ if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
+ verify(mResources, times(1)).getString(title, eq(any()));
+ } else {
+ verify(mResources, times(1)).getString(title);
+ }
+ verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed);
+ }
+
+ @Test
+ public void testTitleOfPrivateDnsBroken() {
+ // Test the title of mobile data.
+ verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
+ reset(mResources);
+
+ // Test the title of wifi.
+ verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
+ reset(mResources);
+
+ // Test the title of other networks.
+ verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
+ reset(mResources);
+ }
+
@Test
public void testNotificationsShownAndCleared() {
final int NETWORK_ID_BASE = 100;
diff --git a/tools/genprotos.sh b/tools/genprotos.sh
deleted file mode 100755
index f901c9f..0000000
--- a/tools/genprotos.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-# TODO This should not be needed. If you set a custom OUT_DIR or OUT_DIR_COMMON_BASE you can
-# end up with a command that is extremely long, potentially going passed MAX_ARG_STRLEN due to
-# the way sbox rewrites the command. See b/70221552.
-
-set -e
-
-location_aprotoc=$1
-location_protoc=$2
-location_soong_zip=$3
-genDir=$4
-depfile=$5
-in=$6
-out=$7
-
-mkdir -p ${genDir}/${in} && \
- ${location_aprotoc} --plugin=${location_protoc} \
- --dependency_out=${depfile} \
- --javastream_out=${genDir}/${in} \
- -Iexternal/protobuf/src \
- -I . \
- ${in} && \
- ${location_soong_zip} -jar -o ${out} -C ${genDir}/${in} -D ${genDir}/${in}
diff --git a/tools/processors/unsupportedappusage/Android.bp b/tools/processors/unsupportedappusage/Android.bp
index 0e33fdd..1e96234 100644
--- a/tools/processors/unsupportedappusage/Android.bp
+++ b/tools/processors/unsupportedappusage/Android.bp
@@ -1,11 +1,6 @@
-java_plugin {
- name: "unsupportedappusage-annotation-processor",
- processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor",
-
- java_resources: [
- "META-INF/**/*",
- ],
+java_library_host {
+ name: "unsupportedappusage-annotation-processor-lib",
srcs: [
"src/**/*.java",
],
@@ -22,6 +17,18 @@
"--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
],
},
+}
+
+java_plugin {
+ name: "unsupportedappusage-annotation-processor",
+ processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor",
+
+ java_resources: [
+ "META-INF/**/*",
+ ],
+ static_libs: [
+ "unsupportedappusage-annotation-processor-lib"
+ ],
use_tools_jar: true,
}
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
index 5a5703e..65fc733 100644
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
+++ b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
@@ -101,14 +101,20 @@
private String getClassSignature(TypeElement clazz) {
StringBuilder sb = new StringBuilder("L");
for (Element enclosing : getEnclosingElements(clazz)) {
- if (enclosing.getKind() == PACKAGE) {
- sb.append(((PackageElement) enclosing)
- .getQualifiedName()
- .toString()
- .replace('.', '/'));
- sb.append('/');
- } else {
- sb.append(enclosing.getSimpleName()).append('$');
+ switch (enclosing.getKind()) {
+ case MODULE:
+ // ignore this.
+ break;
+ case PACKAGE:
+ sb.append(((PackageElement) enclosing)
+ .getQualifiedName()
+ .toString()
+ .replace('.', '/'));
+ sb.append('/');
+ break;
+ default:
+ sb.append(enclosing.getSimpleName()).append('$');
+ break;
}
}
diff --git a/tools/processors/unsupportedappusage/test/Android.bp b/tools/processors/unsupportedappusage/test/Android.bp
new file mode 100644
index 0000000..49ea3d4
--- /dev/null
+++ b/tools/processors/unsupportedappusage/test/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2019 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.
+
+java_test_host {
+ name: "unsupportedappusage-processor-test",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "libjavac",
+ "unsupportedappusage-annotation-processor-lib",
+ "truth-host-prebuilt",
+ "mockito-host",
+ "junit-host",
+ "objenesis",
+ ],
+}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
new file mode 100644
index 0000000..23db99e
--- /dev/null
+++ b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 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.processor.unsupportedappusage;
+
+import com.google.common.base.Splitter;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CsvReader {
+
+ private final Splitter mSplitter;
+ private final List<String> mColumns;
+ private final List<Map<String, String>> mContents;
+
+ public CsvReader(InputStream in) throws IOException {
+ mSplitter = Splitter.on(",");
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ mColumns = mSplitter.splitToList(br.readLine());
+ mContents = new ArrayList<>();
+ String line = br.readLine();
+ while (line != null) {
+ List<String> contents = mSplitter.splitToList(line);
+ Map<String, String> contentMap = new HashMap<>();
+ for (int i = 0; i < Math.min(contents.size(), mColumns.size()); ++i) {
+ contentMap.put(mColumns.get(i), contents.get(i));
+ }
+ mContents.add(contentMap);
+ line = br.readLine();
+ }
+ br.close();
+ }
+
+ public List<String> getColumns() {
+ return mColumns;
+ }
+
+ public List<Map<String, String>> getContents() {
+ return mContents;
+ }
+}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
new file mode 100644
index 0000000..012e88f
--- /dev/null
+++ b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 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.processor.unsupportedappusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.javac.Javac;
+
+import com.google.common.base.Joiner;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class UnsupportedAppUsageProcessorTest {
+
+ private Javac mJavac;
+
+ @Before
+ public void setup() throws IOException {
+ mJavac = new Javac();
+ mJavac.addSource("dalvik.annotation.compat.UnsupportedAppUsage", Joiner.on('\n').join(
+ "package dalvik.annotation.compat;",
+ "public @interface UnsupportedAppUsage {",
+ " String expectedSignature() default \"\";\n",
+ " String someProperty() default \"\";",
+ "}"));
+ }
+
+ private CsvReader compileAndReadCsv() throws IOException {
+ mJavac.compileWithAnnotationProcessor(new UnsupportedAppUsageProcessor());
+ return new CsvReader(
+ mJavac.getOutputFile("unsupportedappusage/unsupportedappusage_index.csv"));
+ }
+
+ @Test
+ public void testSignatureFormat() throws Exception {
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;",
+ "import dalvik.annotation.compat.UnsupportedAppUsage;",
+ "public class Class {",
+ " @UnsupportedAppUsage",
+ " public void method() {}",
+ "}"));
+ assertThat(compileAndReadCsv().getContents().get(0)).containsEntry(
+ "signature", "La/b/Class;->method()V"
+ );
+ }
+
+ @Test
+ public void testSourcePosition() throws Exception {
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;", // 1
+ "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
+ "public class Class {", // 3
+ " @UnsupportedAppUsage", // 4
+ " public void method() {}", // 5
+ "}"));
+ Map<String, String> row = compileAndReadCsv().getContents().get(0);
+ assertThat(row).containsEntry("startline", "4");
+ assertThat(row).containsEntry("startcol", "3");
+ assertThat(row).containsEntry("endline", "4");
+ assertThat(row).containsEntry("endcol", "23");
+ }
+
+ @Test
+ public void testAnnotationProperties() throws Exception {
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;", // 1
+ "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
+ "public class Class {", // 3
+ " @UnsupportedAppUsage(someProperty=\"value\")", // 4
+ " public void method() {}", // 5
+ "}"));
+ assertThat(compileAndReadCsv().getContents().get(0)).containsEntry(
+ "properties", "someProperty=%22value%22");
+ }
+
+
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 68355c6..b53b2aa 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1128,6 +1128,9 @@
*/
private static final int MAX_ACTIVE_LOCKS = 50;
+ /** Indicates an invalid SSID. */
+ public static final String UNKNOWN_SSID = "<unknown ssid>";
+
/* Number of currently active WifiLocks and MulticastLocks */
@UnsupportedAppUsage
private int mActiveLockCount;
@@ -2326,7 +2329,7 @@
* <p>
* In the connected state, access to the SSID and BSSID requires
* the same permissions as {@link #getScanResults}. If such access is not allowed,
- * {@link WifiInfo#getSSID} will return {@code "<unknown ssid>"} and
+ * {@link WifiInfo#getSSID} will return {@link #UNKNOWN_SSID} and
* {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
*
* @return the Wi-Fi information, contained in {@link WifiInfo}.
@@ -3117,7 +3120,7 @@
/**
* Base class for soft AP callback. Should be extended by applications and set when calling
- * {@link WifiManager#registerSoftApCallback(SoftApCallback, Handler)}.
+ * {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
*
* @hide
*/
@@ -3197,16 +3200,16 @@
* without the permission will trigger a {@link java.lang.SecurityException}.
* <p>
*
- * @param callback Callback for soft AP events
* @param executor The executor to execute the callbacks of the {@code executor}
* object. If null, then the application's main executor will be used.
+ * @param callback Callback for soft AP events
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void registerSoftApCallback(@NonNull SoftApCallback callback,
- @Nullable @CallbackExecutor Executor executor) {
+ public void registerSoftApCallback(@Nullable @CallbackExecutor Executor executor,
+ @NonNull SoftApCallback callback) {
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index b22ae070..5a212a8 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
import android.net.ScoredNetwork;
import android.os.Handler;
import android.os.Process;
@@ -40,7 +41,8 @@
*
* @hide
*/
-public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
+public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
+ implements NetworkScoreManager.NetworkScoreCallback {
private static final String TAG = "WifiNetworkScoreCache";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
@@ -246,6 +248,17 @@
}
@Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ dumpWithLatestScanResults(fd, writer, args, wifiManager.getScanResults());
+ }
+
+ /**
+ * This is directly invoked from within Wifi-Service (on it's instance of this class), hence
+ * avoid making the WifiManager.getScanResults() call to avoid a deadlock.
+ */
+ public final void dumpWithLatestScanResults(
+ FileDescriptor fd, PrintWriter writer, String[] args,
+ List<ScanResult> latestScanResults) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
String header = String.format("WifiNetworkScoreCache (%s/%d)",
mContext.getPackageName(), Process.myUid());
@@ -256,8 +269,7 @@
writer.println(" " + score);
}
writer.println(" Network scores for latest ScanResults:");
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- for (ScanResult scanResult : wifiManager.getScanResults()) {
+ for (ScanResult scanResult : latestScanResults) {
writer.println(
" " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
}
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index 70ca088..f187e10 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -48,7 +48,7 @@
private static final int HEX_RADIX = 16;
@UnsupportedAppUsage
- public static final String NONE = "<unknown ssid>";
+ public static final String NONE = WifiManager.UNKNOWN_SSID;
private WifiSsid() {
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index cfdb6f1..4260c20 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -686,7 +686,7 @@
@Test
public void registerSoftApCallbackThrowsIllegalArgumentExceptionOnNullArgumentForCallback() {
try {
- mWifiManager.registerSoftApCallback(null, new HandlerExecutor(mHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), null);
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
@@ -710,7 +710,7 @@
@Test
public void registerSoftApCallbackUsesMainLooperOnNullArgumentForHandler() {
when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
- mWifiManager.registerSoftApCallback(mSoftApCallback, null);
+ mWifiManager.registerSoftApCallback(null, mSoftApCallback);
verify(mContext).getMainExecutor();
}
@@ -719,7 +719,7 @@
*/
@Test
public void registerSoftApCallbackCallGoesToWifiServiceImpl() throws Exception {
- mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
verify(mWifiService).registerSoftApCallback(any(IBinder.class),
any(ISoftApCallback.Stub.class), anyInt());
}
@@ -730,7 +730,7 @@
@Test
public void unregisterSoftApCallbackCallGoesToWifiServiceImpl() throws Exception {
ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
- mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
verify(mWifiService).registerSoftApCallback(any(IBinder.class),
any(ISoftApCallback.Stub.class), callbackIdentifier.capture());
@@ -745,7 +745,7 @@
public void softApCallbackProxyCallsOnStateChanged() throws Exception {
ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
- mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
anyInt());
@@ -761,7 +761,7 @@
public void softApCallbackProxyCallsOnConnectedClientsChanged() throws Exception {
ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
- mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
anyInt());
@@ -778,7 +778,7 @@
public void softApCallbackProxyCallsOnMultipleUpdates() throws Exception {
ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
- mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
anyInt());
@@ -802,7 +802,7 @@
ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
TestLooper altLooper = new TestLooper();
Handler altHandler = new Handler(altLooper.getLooper());
- mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(altHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(altHandler), mSoftApCallback);
verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
anyInt());
@@ -816,7 +816,7 @@
*/
@Test
public void testCorrectLooperIsUsedForSoftApCallbackHandler() throws Exception {
- mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
mLooper.dispatchAll();
verify(mWifiService).registerSoftApCallback(any(IBinder.class),
any(ISoftApCallback.Stub.class), anyInt());