From aa2b287cbf687adaab257139f8a72ceeb160dc6a Mon Sep 17 00:00:00 2001 From: Stanislav Baranov Date: Thu, 21 Feb 2019 13:45:24 -0800 Subject: [PATCH] Reland #7777 with proper LICENSE (#7888) --- ci/licenses.sh | 4 +- ci/licenses_golden/licenses_flutter | 33 ++++++- shell/platform/android/BUILD.gn | 4 + .../io/flutter/view/ResourceExtractor.java | 67 ++++++++------ sky/packages/sky_engine/LICENSE | 26 ++++++ third_party/bsdiff/LICENSE | 23 +++++ third_party/bsdiff/README.md | 12 +++ .../bsdiff/io/flutter/util/BSDiff.java | 91 +++++++++++++++++++ 8 files changed, 232 insertions(+), 28 deletions(-) create mode 100644 third_party/bsdiff/LICENSE create mode 100644 third_party/bsdiff/README.md create mode 100644 third_party/bsdiff/io/flutter/util/BSDiff.java diff --git a/ci/licenses.sh b/ci/licenses.sh index a8452f36edc..fe56fc33148 100755 --- a/ci/licenses.sh +++ b/ci/licenses.sh @@ -42,7 +42,7 @@ fi echo "Checking license count in licenses_flutter..." actualLicenseCount=`tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9'` -expectedLicenseCount=2 # When changing this number: Update the error message below as well describing all expected license types. +expectedLicenseCount=3 # When changing this number: Update the error message below as well describing all expected license types. if [ "$actualLicenseCount" -ne "$expectedLicenseCount" ] then @@ -53,6 +53,8 @@ then echo "double-check that all newly added files have a BSD-style license" echo "header with the following copyright:" echo " Copyright 2013 The Flutter Authors. All rights reserved." + echo "Files in 'third_party/bsdiff' may have the following copyright instead:" + echo " Copyright 2003-2005 Colin Percival. All rights reserved." echo "Files in 'third_party/txt' may have an Apache license header instead." echo "If you're absolutely sure that the change in license count is" echo "intentional, update 'flutter/ci/licenses.sh' with the new count." diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 3d9c0638245..31ba579d957 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -4,6 +4,37 @@ UNUSED LICENSES: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USED LICENSES: +==================================================================================================== +LIBRARY: bsdiff +ORIGIN: ../../../flutter/third_party/bsdiff/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/bsdiff/io/flutter/util/BSDiff.java +---------------------------------------------------------------------------------------------------- +Copyright 2003-2005 Colin Percival. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: engine LIBRARY: txt @@ -981,4 +1012,4 @@ 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. ==================================================================================================== -Total license count: 2 +Total license count: 3 diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index ea6ee243977..966cd814659 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -168,6 +168,10 @@ java_library("flutter_shell_java") { "io/flutter/view/VsyncWaiter.java", ] + java_files += [ + "$flutter_root/third_party/bsdiff/io/flutter/util/BSDiff.java", + ] + deps = [ ":android_support_v13", ":android_support_annotations", diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index a0e2f0965ad..b44bace5f0a 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -11,6 +11,7 @@ import android.content.res.AssetManager; import android.os.AsyncTask; import android.os.Build; import android.util.Log; +import io.flutter.util.BSDiff; import io.flutter.util.PathUtils; import org.json.JSONObject; @@ -19,6 +20,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; +import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -29,8 +31,6 @@ class ResourceExtractor { private static final String TAG = "ResourceExtractor"; private static final String TIMESTAMP_PREFIX = "res_timestamp-"; - private static final int BUFFER_SIZE = 16 * 1024; - @SuppressWarnings("deprecation") static long getVersionCode(PackageInfo packageInfo) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { @@ -177,7 +177,6 @@ class ResourceExtractor { private boolean extractAPK(File dataDir) { final AssetManager manager = mContext.getResources().getAssets(); - byte[] buffer = null; for (String asset : mResources) { try { final File output = new File(dataDir, asset); @@ -190,19 +189,11 @@ class ResourceExtractor { try (InputStream is = manager.open(asset); OutputStream os = new FileOutputStream(output)) { - if (buffer == null) { - buffer = new byte[BUFFER_SIZE]; - } - - int count = 0; - while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { - os.write(buffer, 0, count); - } - - os.flush(); - Log.i(TAG, "Extracted baseline resource " + asset); + copy(is, os); } + Log.i(TAG, "Extracted baseline resource " + asset); + } catch (FileNotFoundException fnfe) { continue; @@ -219,6 +210,8 @@ class ResourceExtractor { /// Returns true if successfully unpacked update resources or if there is no update, /// otherwise deletes all resources and returns false. private boolean extractUpdate(File dataDir) { + final AssetManager manager = mContext.getResources().getAssets(); + ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater(); if (resourceUpdater == null) { return true; @@ -245,11 +238,15 @@ class ResourceExtractor { return false; } - byte[] buffer = null; for (String asset : mResources) { + boolean useDiff = false; ZipEntry entry = zipFile.getEntry(asset); if (entry == null) { - continue; + useDiff = true; + entry = zipFile.getEntry(asset + ".bzdiff40"); + if (entry == null) { + continue; + } } final File output = new File(dataDir, asset); @@ -260,18 +257,29 @@ class ResourceExtractor { output.getParentFile().mkdirs(); } - try (InputStream is = zipFile.getInputStream(entry); - OutputStream os = new FileOutputStream(output)) { - if (buffer == null) { - buffer = new byte[BUFFER_SIZE]; + try { + if (useDiff) { + ByteArrayOutputStream diff = new ByteArrayOutputStream(); + try (InputStream is = zipFile.getInputStream(entry)) { + copy(is, diff); + } + + ByteArrayOutputStream orig = new ByteArrayOutputStream(); + try (InputStream is = manager.open(asset)) { + copy(is, orig); + } + + try (OutputStream os = new FileOutputStream(output)) { + os.write(BSDiff.bspatch(orig.toByteArray(), diff.toByteArray())); + } + + } else { + try (InputStream is = zipFile.getInputStream(entry); + OutputStream os = new FileOutputStream(output)) { + copy(is, os); + } } - int count = 0; - while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { - os.write(buffer, 0, count); - } - - os.flush(); Log.i(TAG, "Extracted override resource " + asset); } catch (FileNotFoundException fnfe) { @@ -339,4 +347,11 @@ class ResourceExtractor { return null; } + + private static void copy(InputStream in, OutputStream out) throws IOException { + byte[] buf = new byte[16 * 1024]; + for (int i; (i = in.read(buf)) >= 0; ) { + out.write(buf, 0, i); + } + } } diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index edab381ceab..265bc32f112 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -3492,6 +3492,32 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- +bsdiff + +Copyright 2003-2005 Colin Percival. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- engine txt diff --git a/third_party/bsdiff/LICENSE b/third_party/bsdiff/LICENSE new file mode 100644 index 00000000000..d04a5299655 --- /dev/null +++ b/third_party/bsdiff/LICENSE @@ -0,0 +1,23 @@ +Copyright 2003-2005 Colin Percival. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/bsdiff/README.md b/third_party/bsdiff/README.md new file mode 100644 index 00000000000..79aac03d0fc --- /dev/null +++ b/third_party/bsdiff/README.md @@ -0,0 +1,12 @@ +# BSDiff + +Binary diff/patch algorithm based on +[bsdiff 4.3](http://www.daemonology.net/bsdiff/) by Colin Percival. +It's very effective at compressesing incremental changes in binaries. + +This implementation has the following differences from Colin's code, +to make it easier to read and apply patches in Java and Objective C: + +* Using gzip instead of bzip2 because gzip is included in JDK by default +* Using big- instead of little-endian serialization to simplify Java code +* Using two's complement instead of high-bit coding for negatives numbers diff --git a/third_party/bsdiff/io/flutter/util/BSDiff.java b/third_party/bsdiff/io/flutter/util/BSDiff.java new file mode 100644 index 00000000000..135882033cb --- /dev/null +++ b/third_party/bsdiff/io/flutter/util/BSDiff.java @@ -0,0 +1,91 @@ +// Copyright 2003-2005 Colin Percival. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.util; + +import java.io.*; +import java.util.zip.GZIPInputStream; + +/** + * This is a Java port of algorithm from Flutter framework bsdiff.dart. + * Note that this port uses 32-bit ints, which limits data size to 2GB. + **/ +public abstract class BSDiff { + public static byte[] bspatch(byte[] olddata, byte[] diffdata) throws IOException { + InputStream in = new ByteArrayInputStream(diffdata, 0, diffdata.length); + DataInputStream header = new DataInputStream(in); + + byte[] magic = new byte[8]; + header.read(magic); + if (!new String(magic).equals("BZDIFF40")) { + throw new IOException("Invalid magic"); + } + + int ctrllen = (int) header.readLong(); + int datalen = (int) header.readLong(); + int newsize = (int) header.readLong(); + header.close(); + + in = new ByteArrayInputStream(diffdata, 0, diffdata.length); + in.skip(32); + DataInputStream cpf = new DataInputStream(new GZIPInputStream(in)); + + in = new ByteArrayInputStream(diffdata, 0, diffdata.length); + in.skip(32 + ctrllen); + InputStream dpf = new GZIPInputStream(in); + + in = new ByteArrayInputStream(diffdata, 0, diffdata.length); + in.skip(32 + ctrllen + datalen); + InputStream epf = new GZIPInputStream(in); + + byte[] newdata = new byte[newsize]; + + int oldpos = 0; + int newpos = 0; + + while (newpos < newsize) { + int[] ctrl = new int[3]; + for (int i = 0; i <= 2; i++) { + ctrl[i] = (int) cpf.readLong(); + } + if (newpos + ctrl[0] > newsize) { + throw new IOException("Invalid ctrl[0]"); + } + + read(dpf, newdata, newpos, ctrl[0]); + + for (int i = 0; i < ctrl[0]; i++) { + if ((oldpos + i >= 0) && (oldpos + i < olddata.length)) { + newdata[newpos + i] += olddata[oldpos + i]; + } + } + + newpos += ctrl[0]; + oldpos += ctrl[0]; + + if (newpos + ctrl[1] > newsize) { + throw new IOException("Invalid ctrl[0]"); + } + + read(epf, newdata, newpos, ctrl[1]); + + newpos += ctrl[1]; + oldpos += ctrl[2]; + } + + cpf.close(); + dpf.close(); + epf.close(); + + return newdata; + } + + private static void read(InputStream in, byte[] buf, int off, int len) throws IOException { + for (int i, n = 0; n < len; n += i) { + if ((i = in.read(buf, off + n, len - n)) < 0) { + throw new IOException("Unexpected EOF"); + } + } + } +}