Merge "Fix race with Asset destruction and printing allocation stats"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index aba53dc..718f141 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -84,6 +84,7 @@
public final class Pm {
private static final String TAG = "Pm";
+ private static final String STDIN_PATH = "-";
IPackageManager mPm;
IPackageInstaller mInstaller;
@@ -403,7 +404,7 @@
private int runInstall() throws RemoteException {
final InstallParams params = makeInstallParams();
final String inPath = nextArg();
- if (params.sessionParams.sizeBytes < 0 && inPath != null) {
+ if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
File file = new File(inPath);
if (file.isFile()) {
try {
@@ -413,9 +414,12 @@
PackageHelper.calculateInstalledSize(pkgLite, false,
params.sessionParams.abiOverride));
} catch (PackageParserException | IOException e) {
- System.err.println("Error: Failed to parse APK file : " + e);
+ System.err.println("Error: Failed to parse APK file: " + e);
return 1;
}
+ } else {
+ System.err.println("Error: Can't open non-file: " + inPath);
+ return 1;
}
}
@@ -423,7 +427,7 @@
params.installerPackageName, params.userId);
try {
- if (inPath == null && params.sessionParams.sizeBytes == 0) {
+ if (inPath == null && params.sessionParams.sizeBytes == -1) {
System.err.println("Error: must either specify a package size or an APK file");
return 1;
}
@@ -540,7 +544,11 @@
}
break;
case "-S":
- sessionParams.setSize(Long.parseLong(nextOptionData()));
+ final long sizeBytes = Long.parseLong(nextOptionData());
+ if (sizeBytes <= 0) {
+ throw new IllegalArgumentException("Size must be positive");
+ }
+ sessionParams.setSize(sizeBytes);
break;
case "--abi":
sessionParams.abiOverride = checkAbiArgument(nextOptionData());
@@ -585,7 +593,7 @@
private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
boolean logSuccess) throws RemoteException {
- if ("-".equals(inPath)) {
+ if (STDIN_PATH.equals(inPath)) {
inPath = null;
} else if (inPath != null) {
final File file = new File(inPath);
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 2f9178c..4aeb40c 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -16,8 +16,11 @@
package android.hardware.usb;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
/**
* A class representing a USB accessory, which is an external hardware component
@@ -46,12 +49,12 @@
private static final String TAG = "UsbAccessory";
- private final String mManufacturer;
- private final String mModel;
- private final String mDescription;
- private final String mVersion;
- private final String mUri;
- private final String mSerial;
+ private final @NonNull String mManufacturer;
+ private final @NonNull String mModel;
+ private final @Nullable String mDescription;
+ private final @Nullable String mVersion;
+ private final @Nullable String mUri;
+ private final @Nullable String mSerial;
/** @hide */
public static final int MANUFACTURER_STRING = 0;
@@ -70,10 +73,11 @@
* UsbAccessory should only be instantiated by UsbService implementation
* @hide
*/
- public UsbAccessory(String manufacturer, String model, String description,
- String version, String uri, String serial) {
- mManufacturer = manufacturer;
- mModel = model;
+ public UsbAccessory(@NonNull String manufacturer, @NonNull String model,
+ @Nullable String description, @Nullable String version, @Nullable String uri,
+ @Nullable String serial) {
+ mManufacturer = Preconditions.checkNotNull(manufacturer);
+ mModel = Preconditions.checkNotNull(model);
mDescription = description;
mVersion = version;
mUri = uri;
@@ -85,12 +89,8 @@
* @hide
*/
public UsbAccessory(String[] strings) {
- mManufacturer = strings[MANUFACTURER_STRING];
- mModel = strings[MODEL_STRING];
- mDescription = strings[DESCRIPTION_STRING];
- mVersion = strings[VERSION_STRING];
- mUri = strings[URI_STRING];
- mSerial = strings[SERIAL_STRING];
+ this(strings[MANUFACTURER_STRING], strings[MODEL_STRING], strings[DESCRIPTION_STRING],
+ strings[VERSION_STRING], strings[URI_STRING], strings[SERIAL_STRING]);
}
/**
@@ -98,7 +98,7 @@
*
* @return the accessory manufacturer
*/
- public String getManufacturer() {
+ public @NonNull String getManufacturer() {
return mManufacturer;
}
@@ -107,25 +107,25 @@
*
* @return the accessory model
*/
- public String getModel() {
+ public @NonNull String getModel() {
return mModel;
}
/**
* Returns a user visible description of the accessory.
*
- * @return the accessory description
+ * @return the accessory description, or {@code null} if not set
*/
- public String getDescription() {
+ public @Nullable String getDescription() {
return mDescription;
}
/**
* Returns the version of the accessory.
*
- * @return the accessory version
+ * @return the accessory version, or {@code null} if not set
*/
- public String getVersion() {
+ public @Nullable String getVersion() {
return mVersion;
}
@@ -134,9 +134,9 @@
* This is an optional URI that might show information about the accessory
* or provide the option to download an application for the accessory
*
- * @return the accessory URI
+ * @return the accessory URI, or {@code null} if not set
*/
- public String getUri() {
+ public @Nullable String getUri() {
return mUri;
}
@@ -145,9 +145,9 @@
* This is an optional serial number that can be used to differentiate
* between individual accessories of the same model and manufacturer
*
- * @return the unique serial number
+ * @return the unique serial number, or {@code null} if not set
*/
- public String getSerial() {
+ public @Nullable String getSerial() {
return mSerial;
}
@@ -172,12 +172,10 @@
@Override
public int hashCode() {
- return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
- (mModel == null ? 0 : mModel.hashCode()) ^
+ return mManufacturer.hashCode() ^ mModel.hashCode() ^
(mDescription == null ? 0 : mDescription.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode()) ^
- (mUri == null ? 0 : mUri.hashCode()) ^
- (mSerial == null ? 0 : mSerial.hashCode()));
+ (mUri == null ? 0 : mUri.hashCode()) ^ (mSerial == null ? 0 : mSerial.hashCode());
}
@Override
diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java
index da5c128..a171570 100644
--- a/core/java/android/hardware/usb/UsbConfiguration.java
+++ b/core/java/android/hardware/usb/UsbConfiguration.java
@@ -16,8 +16,11 @@
package android.hardware.usb;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
/**
* A class representing a configuration on a {@link UsbDevice}.
@@ -35,20 +38,20 @@
public class UsbConfiguration implements Parcelable {
private final int mId;
- private final String mName;
+ private final @Nullable String mName;
private final int mAttributes;
private final int mMaxPower;
- private Parcelable[] mInterfaces;
+
+ /** All interfaces for this config, only null during creation */
+ private @Nullable Parcelable[] mInterfaces;
/**
* Mask for "self-powered" bit in the configuration's attributes.
- * @see #getAttributes
*/
private static final int ATTR_SELF_POWERED = 1 << 6;
/**
* Mask for "remote wakeup" bit in the configuration's attributes.
- * @see #getAttributes
*/
private static final int ATTR_REMOTE_WAKEUP = 1 << 5;
@@ -56,7 +59,7 @@
* UsbConfiguration should only be instantiated by UsbService implementation
* @hide
*/
- public UsbConfiguration(int id, String name, int attributes, int maxPower) {
+ public UsbConfiguration(int id, @Nullable String name, int attributes, int maxPower) {
mId = id;
mName = name;
mAttributes = attributes;
@@ -76,9 +79,9 @@
/**
* Returns the configuration's name.
*
- * @return the configuration's name
+ * @return the configuration's name, or {@code null} if the property could not be read
*/
- public String getName() {
+ public @Nullable String getName() {
return mName;
}
@@ -125,7 +128,7 @@
*
* @return the interface
*/
- public UsbInterface getInterface(int index) {
+ public @NonNull UsbInterface getInterface(int index) {
return (UsbInterface)mInterfaces[index];
}
@@ -133,8 +136,8 @@
* Only used by UsbService implementation
* @hide
*/
- public void setInterfaces(Parcelable[] interfaces) {
- mInterfaces = interfaces;
+ public void setInterfaces(@NonNull Parcelable[] interfaces) {
+ mInterfaces = Preconditions.checkArrayElementsNotNull(interfaces, "interfaces");
}
@Override
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 410d550..425a89d 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -16,8 +16,11 @@
package android.hardware.usb;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
/**
* This class represents a USB device attached to the android device with the android device
@@ -42,29 +45,31 @@
private static final String TAG = "UsbDevice";
private static final boolean DEBUG = false;
- private final String mName;
- private final String mManufacturerName;
- private final String mProductName;
- private final String mVersion;
- private final String mSerialNumber;
+ private final @NonNull String mName;
+ private final @Nullable String mManufacturerName;
+ private final @Nullable String mProductName;
+ private final @NonNull String mVersion;
+ private final @Nullable String mSerialNumber;
private final int mVendorId;
private final int mProductId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
- private Parcelable[] mConfigurations;
- // list of all interfaces on the device
- private UsbInterface[] mInterfaces;
+ /** All configurations for this device, only null during creation */
+ private @Nullable Parcelable[] mConfigurations;
+
+ /** All interfaces on the device. Initialized on first call to getInterfaceList */
+ private @Nullable UsbInterface[] mInterfaces;
/**
* UsbDevice should only be instantiated by UsbService implementation
* @hide
*/
- public UsbDevice(String name, int vendorId, int productId,
- int Class, int subClass, int protocol,
- String manufacturerName, String productName, String version, String serialNumber) {
- mName = name;
+ public UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass,
+ int protocol, @Nullable String manufacturerName, @Nullable String productName,
+ @NonNull String version, @Nullable String serialNumber) {
+ mName = Preconditions.checkNotNull(name);
mVendorId = vendorId;
mProductId = productId;
mClass = Class;
@@ -72,7 +77,7 @@
mProtocol = protocol;
mManufacturerName = manufacturerName;
mProductName = productName;
- mVersion = version;
+ mVersion = Preconditions.checkStringNotEmpty(version);
mSerialNumber = serialNumber;
}
@@ -83,25 +88,25 @@
*
* @return the device name
*/
- public String getDeviceName() {
+ public @NonNull String getDeviceName() {
return mName;
}
/**
* Returns the manufacturer name of the device.
*
- * @return the manufacturer name
+ * @return the manufacturer name, or {@code null} if the property could not be read
*/
- public String getManufacturerName() {
+ public @Nullable String getManufacturerName() {
return mManufacturerName;
}
/**
* Returns the product name of the device.
*
- * @return the product name
+ * @return the product name, or {@code null} if the property could not be read
*/
- public String getProductName() {
+ public @Nullable String getProductName() {
return mProductName;
}
@@ -110,16 +115,16 @@
*
* @return the device version
*/
- public String getVersion() {
+ public @NonNull String getVersion() {
return mVersion;
}
/**
* Returns the serial number of the device.
*
- * @return the serial number name
+ * @return the serial number name, or {@code null} if the property could not be read
*/
- public String getSerialNumber() {
+ public @Nullable String getSerialNumber() {
return mSerialNumber;
}
@@ -195,11 +200,11 @@
*
* @return the configuration
*/
- public UsbConfiguration getConfiguration(int index) {
+ public @NonNull UsbConfiguration getConfiguration(int index) {
return (UsbConfiguration)mConfigurations[index];
}
- private UsbInterface[] getInterfaceList() {
+ private @Nullable UsbInterface[] getInterfaceList() {
if (mInterfaces == null) {
int configurationCount = mConfigurations.length;
int interfaceCount = 0;
@@ -240,7 +245,7 @@
*
* @return the interface
*/
- public UsbInterface getInterface(int index) {
+ public @NonNull UsbInterface getInterface(int index) {
return getInterfaceList()[index];
}
@@ -248,8 +253,8 @@
* Only used by UsbService implementation
* @hide
*/
- public void setConfigurations(Parcelable[] configuration) {
- mConfigurations = configuration;
+ public void setConfigurations(@NonNull Parcelable[] configuration) {
+ mConfigurations = Preconditions.checkArrayElementsNotNull(configuration, "configuration");
}
@Override
diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java
index de01a88..4b5278c 100644
--- a/core/java/android/hardware/usb/UsbInterface.java
+++ b/core/java/android/hardware/usb/UsbInterface.java
@@ -16,8 +16,10 @@
package android.hardware.usb;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
/**
* A class representing an interface on a {@link UsbDevice}.
@@ -36,17 +38,19 @@
private final int mId;
private final int mAlternateSetting;
- private final String mName;
+ private @Nullable final String mName;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
+
+ /** All endpoints of this interface, only null during creation */
private Parcelable[] mEndpoints;
/**
* UsbInterface should only be instantiated by UsbService implementation
* @hide
*/
- public UsbInterface(int id, int alternateSetting, String name,
+ public UsbInterface(int id, int alternateSetting, @Nullable String name,
int Class, int subClass, int protocol) {
mId = id;
mAlternateSetting = alternateSetting;
@@ -83,9 +87,9 @@
/**
* Returns the interface's name.
*
- * @return the interface's name
+ * @return the interface's name, or {@code null} if the property could not be read
*/
- public String getName() {
+ public @Nullable String getName() {
return mName;
}
@@ -140,7 +144,7 @@
* @hide
*/
public void setEndpoints(Parcelable[] endpoints) {
- mEndpoints = endpoints;
+ mEndpoints = Preconditions.checkArrayElementsNotNull(endpoints, "endpoints");
}
@Override
diff --git a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
index 307c6db..0ab56f9 100644
--- a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
@@ -22,6 +22,7 @@
android:gravity="top|center_horizontal"
android:minHeight="@dimen/alert_dialog_title_height">
<ImageView android:id="@+id/icon"
+ android:adjustViewBounds="true"
android:maxHeight="24dp"
android:maxWidth="24dp"
android:layout_marginTop="8dp"
diff --git a/core/res/res/layout-round-watch/alert_dialog_title_material.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
index 7e71e41..e543c9b 100644
--- a/core/res/res/layout-round-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
@@ -21,6 +21,7 @@
android:gravity="top|center_horizontal"
android:minHeight="@dimen/alert_dialog_title_height">
<ImageView android:id="@+id/icon"
+ android:adjustViewBounds="true"
android:maxHeight="24dp"
android:maxWidth="24dp"
android:layout_marginTop="12dp"
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index 8a080d9c..af4207e 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -95,7 +95,7 @@
</style>
<style name="DialogWindowTitle.Material">
- <item name="maxLines">3</item>
+ <item name="maxLines">@empty</item>
<item name="scrollHorizontally">false</item>
<item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item>
<item name="gravity">@integer/config_dialogTextGravity</item>
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 17ad0e3..dbb66d9 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -591,7 +591,7 @@
}
static bool hasMergeableClip(const BakedOpState& state) {
- return state.computedState.clipState
+ return !state.computedState.clipState
|| state.computedState.clipState->mode == ClipMode::Rectangle;
}
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 18c35b3..33ee108 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -22,6 +22,8 @@
#include "Typeface.h"
+#include <pthread.h>
+
#include "MinikinSkia.h"
#include "SkTypeface.h"
#include "SkPaint.h"
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 259686b..347d4a5 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -477,6 +477,35 @@
EXPECT_EQ(4, renderer.getIndex());
}
+RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
+ class RegionClipStopsMergeTestRenderer : public TestRendererBase {
+ public:
+ void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
+ };
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPath path;
+ path.addCircle(200, 200, 200, SkPath::kCW_Direction);
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipPath(&path, SkRegion::kIntersect_Op);
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
+ RegionClipStopsMergeTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex());
+}
+
RENDERTHREAD_TEST(FrameBuilder, textMerging) {
class TextMergingTestRenderer : public TestRendererBase {
public:
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
index 5c22c9b..91dd8a5 100644
--- a/media/jni/audioeffect/Android.mk
+++ b/media/jni/audioeffect/Android.mk
@@ -13,9 +13,6 @@
libnativehelper \
libmedia
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-effects)
-
LOCAL_MODULE:= libaudioeffect_jni
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
index a2e9e94..e948cf7 100644
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -23,6 +23,7 @@
#include <linux/fuse.h>
#include <sys/stat.h>
+#include <sys/uio.h>
#include <map>
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a24217e..834d343 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -75,6 +75,11 @@
import java.util.concurrent.TimeUnit;
class PackageManagerShellCommand extends ShellCommand {
+ /** Path for streaming APK content */
+ private static final String STDIN_PATH = "-";
+ /** Whether or not APK content must be streamed from stdin */
+ private static final boolean FORCE_STREAM_INSTALL = true;
+
final IPackageManager mInterface;
final private WeakHashMap<String, Resources> mResourceCache =
new WeakHashMap<String, Resources>();
@@ -139,30 +144,45 @@
return -1;
}
- private int runInstall() throws RemoteException {
+ private void setParamsSize(InstallParams params, String inPath) {
+ // If we're forced to stream the package, the params size
+ // must be set via command-line argument. There's nothing
+ // to do here.
+ if (FORCE_STREAM_INSTALL) {
+ return;
+ }
final PrintWriter pw = getOutPrintWriter();
- final InstallParams params = makeInstallParams();
- final String inPath = getNextArg();
- if (params.sessionParams.sizeBytes < 0 && inPath != null) {
+ if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
File file = new File(inPath);
if (file.isFile()) {
try {
ApkLite baseApk = PackageParser.parseApkLite(file, 0);
PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
- params.sessionParams.setSize(
- PackageHelper.calculateInstalledSize(pkgLite,false, params.sessionParams.abiOverride));
+ params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
+ pkgLite, false, params.sessionParams.abiOverride));
} catch (PackageParserException | IOException e) {
- pw.println("Error: Failed to parse APK file : " + e);
- return 1;
+ pw.println("Error: Failed to parse APK file: " + file);
+ throw new IllegalArgumentException(
+ "Error: Failed to parse APK file: " + file, e);
}
+ } else {
+ pw.println("Error: Can't open non-file: " + inPath);
+ throw new IllegalArgumentException("Error: Can't open non-file: " + inPath);
}
}
+ }
+ private int runInstall() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ final InstallParams params = makeInstallParams();
+ final String inPath = getNextArg();
+
+ setParamsSize(params, inPath);
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
boolean abandonSession = true;
try {
- if (inPath == null && params.sessionParams.sizeBytes == 0) {
+ if (inPath == null && params.sessionParams.sizeBytes == -1) {
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
@@ -1075,7 +1095,11 @@
}
break;
case "-S":
- sessionParams.setSize(Long.parseLong(getNextArg()));
+ final long sizeBytes = Long.parseLong(getNextArg());
+ if (sizeBytes <= 0) {
+ throw new IllegalArgumentException("Size must be positive");
+ }
+ sessionParams.setSize(sizeBytes);
break;
case "--abi":
sessionParams.abiOverride = checkAbiArgument(getNextArg());
@@ -1180,15 +1204,22 @@
private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
+ if (FORCE_STREAM_INSTALL && inPath != null && !STDIN_PATH.equals(inPath)) {
+ pw.println("Error: APK content must be streamed");
+ return 1;
+ }
+ if (STDIN_PATH.equals(inPath)) {
+ inPath = null;
+ } else if (inPath != null) {
+ final File file = new File(inPath);
+ if (file.isFile()) {
+ sizeBytes = file.length();
+ }
+ }
if (sizeBytes <= 0) {
pw.println("Error: must specify a APK size");
return 1;
}
- if (inPath != null && !"-".equals(inPath)) {
- pw.println("Error: APK content must be streamed");
- return 1;
- }
- inPath = null;
final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index b789e17..af78c05 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -16,6 +16,7 @@
package com.android.server.usb;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index 0dcd1521..610f9bc 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -29,6 +29,8 @@
import java.util.Locale;
import java.util.UUID;
+import java.util.List;
+import java.util.ArrayList;
/**
* Helper to manage the database of the sound models that have been registered on the device.
@@ -40,7 +42,7 @@
static final boolean DBG = false;
private static final String NAME = "sound_model.db";
- private static final int VERSION = 5;
+ private static final int VERSION = 6;
public static interface SoundModelContract {
public static final String TABLE = "sound_model";
@@ -58,15 +60,19 @@
// Table Create Statement
private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
+ SoundModelContract.TABLE + "("
- + SoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
- + SoundModelContract.KEY_VENDOR_UUID + " TEXT, "
+ + SoundModelContract.KEY_MODEL_UUID + " TEXT,"
+ + SoundModelContract.KEY_VENDOR_UUID + " TEXT,"
+ SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER,"
+ SoundModelContract.KEY_TYPE + " INTEGER,"
+ SoundModelContract.KEY_DATA + " BLOB,"
+ SoundModelContract.KEY_RECOGNITION_MODES + " INTEGER,"
+ SoundModelContract.KEY_LOCALE + " TEXT,"
+ SoundModelContract.KEY_HINT_TEXT + " TEXT,"
- + SoundModelContract.KEY_USERS + " TEXT" + ")";
+ + SoundModelContract.KEY_USERS + " TEXT,"
+ + "PRIMARY KEY (" + SoundModelContract.KEY_KEYPHRASE_ID + ","
+ + SoundModelContract.KEY_LOCALE + ","
+ + SoundModelContract.KEY_USERS + ")"
+ + ")";
public DatabaseHelper(Context context) {
super(context, NAME, null, VERSION);
@@ -93,6 +99,44 @@
oldVersion++;
}
}
+ if (oldVersion == 5) {
+ // We need to enforce the new primary key constraint that the
+ // keyphrase id, locale, and users are unique. We have to first pull
+ // everything out of the database, remove duplicates, create the new
+ // table, then push everything back in.
+ String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE;
+ Cursor c = db.rawQuery(selectQuery, null);
+ List<SoundModelRecord> old_records = new ArrayList<SoundModelRecord>();
+ try {
+ if (c.moveToFirst()) {
+ do {
+ try {
+ old_records.add(new SoundModelRecord(5, c));
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to extract V5 record", e);
+ }
+ } while (c.moveToNext());
+ }
+ } finally {
+ c.close();
+ }
+ db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
+ onCreate(db);
+ for (SoundModelRecord record : old_records) {
+ if (!record.violatesV6PrimaryKeyConstraint(old_records)) {
+ try {
+ long return_value = record.writeToDatabase(6, db);
+ if (return_value == -1) {
+ Slog.e(TAG, "Database write failed " + record.modelUuid + ": "
+ + return_value);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to update V6 record " + record.modelUuid, e);
+ }
+ }
+ }
+ oldVersion++;
+ }
}
/**
@@ -279,4 +323,73 @@
}
return users;
}
+
+ private static class SoundModelRecord {
+ public final String modelUuid;
+ public final String vendorUuid;
+ public final int keyphraseId;
+ public final int type;
+ public final byte[] data;
+ public final int recognitionModes;
+ public final String locale;
+ public final String hintText;
+ public final String users;
+
+ public SoundModelRecord(int version, Cursor c) {
+ modelUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
+ if (version >= 5) {
+ vendorUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_VENDOR_UUID));
+ } else {
+ vendorUuid = null;
+ }
+ keyphraseId = c.getInt(c.getColumnIndex(SoundModelContract.KEY_KEYPHRASE_ID));
+ type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
+ data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
+ recognitionModes = c.getInt(c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
+ locale = c.getString(c.getColumnIndex(SoundModelContract.KEY_LOCALE));
+ hintText = c.getString(c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
+ users = c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS));
+ }
+
+ // Check to see if this record conflicts with some other record in the list of records.
+ public boolean violatesV6PrimaryKeyConstraint(List<SoundModelRecord> records) {
+ for (SoundModelRecord record : records) {
+ if (this == record) {
+ continue;
+ }
+ if (keyphraseId == record.keyphraseId
+ && stringComparisonHelper(locale, record.locale)
+ && stringComparisonHelper(users, record.users)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public long writeToDatabase(int version, SQLiteDatabase db) {
+ ContentValues values = new ContentValues();
+ values.put(SoundModelContract.KEY_MODEL_UUID, modelUuid);
+ if (version >= 5) {
+ values.put(SoundModelContract.KEY_VENDOR_UUID, vendorUuid);
+ }
+ values.put(SoundModelContract.KEY_KEYPHRASE_ID, keyphraseId);
+ values.put(SoundModelContract.KEY_TYPE, type);
+ values.put(SoundModelContract.KEY_DATA, data);
+ values.put(SoundModelContract.KEY_RECOGNITION_MODES, recognitionModes);
+ values.put(SoundModelContract.KEY_LOCALE, locale);
+ values.put(SoundModelContract.KEY_HINT_TEXT, hintText);
+ values.put(SoundModelContract.KEY_USERS, users);
+
+ return db.insertWithOnConflict(
+ SoundModelContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+ }
+
+ // Helper for checking string equality - including the case when they are null.
+ static private boolean stringComparisonHelper(String a, String b) {
+ if (a != null) {
+ return a.equals(b);
+ }
+ return a == b;
+ }
+ }
}
diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp
index 54a8e9c..5339285 100644
--- a/tools/aapt/ZipEntry.cpp
+++ b/tools/aapt/ZipEntry.cpp
@@ -23,9 +23,10 @@
#include "ZipEntry.h"
#include <utils/Log.h>
+#include <assert.h>
#include <stdio.h>
#include <string.h>
-#include <assert.h>
+#include <time.h>
using namespace android;