Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
8b5f7763
E
engine
项目概览
sxychenjing
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
8b5f7763
编写于
4月 22, 2019
作者:
S
Stanislav Baranov
提交者:
GitHub
4月 22, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Remove support for downloading dynamic patches. (#8663)
上级
1bcb96bf
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
15 addition
and
628 deletion
+15
-628
ci/licenses_golden/licenses_flutter
ci/licenses_golden/licenses_flutter
+0
-1
shell/platform/android/BUILD.gn
shell/platform/android/BUILD.gn
+0
-1
shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
...tform/android/io/flutter/app/FlutterActivityDelegate.java
+0
-10
shell/platform/android/io/flutter/view/FlutterMain.java
shell/platform/android/io/flutter/view/FlutterMain.java
+1
-49
shell/platform/android/io/flutter/view/ResourceExtractor.java
...l/platform/android/io/flutter/view/ResourceExtractor.java
+14
-193
shell/platform/android/io/flutter/view/ResourceUpdater.java
shell/platform/android/io/flutter/view/ResourceUpdater.java
+0
-374
未找到文件。
ci/licenses_golden/licenses_flutter
浏览文件 @
8b5f7763
...
...
@@ -547,7 +547,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourceCleaner.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourceExtractor.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourcePaths.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourceUpdater.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java
FILE: ../../../flutter/shell/platform/android/library_loader.cc
...
...
shell/platform/android/BUILD.gn
浏览文件 @
8b5f7763
...
...
@@ -167,7 +167,6 @@ java_library("flutter_shell_java") {
"io/flutter/view/ResourceCleaner.java",
"io/flutter/view/ResourceExtractor.java",
"io/flutter/view/ResourcePaths.java",
"io/flutter/view/ResourceUpdater.java",
"io/flutter/view/TextureRegistry.java",
"io/flutter/view/VsyncWaiter.java",
]
...
...
shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
浏览文件 @
8b5f7763
...
...
@@ -32,7 +32,6 @@ import io.flutter.view.FlutterMain;
import
io.flutter.view.FlutterNativeView
;
import
io.flutter.view.FlutterRunArguments
;
import
io.flutter.view.FlutterView
;
import
io.flutter.view.ResourceUpdater
;
import
org.json.JSONObject
;
import
java.io.File
;
...
...
@@ -213,7 +212,6 @@ public final class FlutterActivityDelegate
@Override
public
void
onResume
()
{
Application
app
=
(
Application
)
activity
.
getApplicationContext
();
FlutterMain
.
onResume
(
app
);
if
(
app
instanceof
FlutterApplication
)
{
FlutterApplication
flutterApp
=
(
FlutterApplication
)
app
;
flutterApp
.
setCurrentActivity
(
activity
);
...
...
@@ -354,14 +352,6 @@ public final class FlutterActivityDelegate
if
(!
flutterView
.
getFlutterNativeView
().
isApplicationRunning
())
{
FlutterRunArguments
args
=
new
FlutterRunArguments
();
ArrayList
<
String
>
bundlePaths
=
new
ArrayList
<>();
ResourceUpdater
resourceUpdater
=
FlutterMain
.
getResourceUpdater
();
if
(
resourceUpdater
!=
null
)
{
File
patchFile
=
resourceUpdater
.
getInstalledPatch
();
JSONObject
manifest
=
resourceUpdater
.
readManifest
(
patchFile
);
if
(
resourceUpdater
.
validateManifest
(
manifest
))
{
bundlePaths
.
add
(
patchFile
.
getPath
());
}
}
bundlePaths
.
add
(
appBundlePath
);
args
.
bundlePaths
=
bundlePaths
.
toArray
(
new
String
[
0
]);
args
.
entrypoint
=
"main"
;
...
...
shell/platform/android/io/flutter/view/FlutterMain.java
浏览文件 @
8b5f7763
...
...
@@ -74,7 +74,6 @@ public class FlutterMain {
private
static
String
sFlutterAssetsDir
=
DEFAULT_FLUTTER_ASSETS_DIR
;
private
static
boolean
sInitialized
=
false
;
private
static
ResourceUpdater
sResourceUpdater
;
private
static
ResourceExtractor
sResourceExtractor
;
private
static
boolean
sIsPrecompiledAsBlobs
;
private
static
boolean
sIsPrecompiledAsSharedLibrary
;
...
...
@@ -152,17 +151,7 @@ public class FlutterMain {
initAot
(
applicationContext
);
initResources
(
applicationContext
);
if
(
sResourceUpdater
==
null
)
{
System
.
loadLibrary
(
"flutter"
);
}
else
{
sResourceExtractor
.
waitForCompletion
();
File
lib
=
new
File
(
PathUtils
.
getDataDirectory
(
applicationContext
),
DEFAULT_LIBRARY
);
if
(
lib
.
exists
())
{
System
.
load
(
lib
.
getAbsolutePath
());
}
else
{
System
.
loadLibrary
(
"flutter"
);
}
}
System
.
loadLibrary
(
"flutter"
);
// We record the initialization time using SystemClock because at the start of the
// initialization we have not yet loaded the native library to call into dart_tools_api.h.
...
...
@@ -310,21 +299,6 @@ public class FlutterMain {
Log
.
e
(
TAG
,
"Unable to read application info"
,
e
);
}
if
(
metaData
!=
null
&&
metaData
.
getBoolean
(
"DynamicPatching"
))
{
sResourceUpdater
=
new
ResourceUpdater
(
context
);
// Also checking for ON_RESUME here since it's more efficient than waiting for actual
// onResume. Even though actual onResume is imminent when the app has just restarted,
// it's better to start downloading now, in parallel with the rest of initialization,
// and avoid a second application restart a bit later when actual onResume happens.
if
(
sResourceUpdater
.
getDownloadMode
()
==
ResourceUpdater
.
DownloadMode
.
ON_RESTART
||
sResourceUpdater
.
getDownloadMode
()
==
ResourceUpdater
.
DownloadMode
.
ON_RESUME
)
{
sResourceUpdater
.
startUpdateDownloadOnce
();
if
(
sResourceUpdater
.
getInstallMode
()
==
ResourceUpdater
.
InstallMode
.
IMMEDIATE
)
{
sResourceUpdater
.
waitForDownloadCompletion
();
}
}
}
sResourceExtractor
=
new
ResourceExtractor
(
context
);
sResourceExtractor
...
...
@@ -346,22 +320,9 @@ public class FlutterMain {
.
addResource
(
sAotIsolateSnapshotInstr
);
}
if
(
sResourceUpdater
!=
null
)
{
sResourceExtractor
.
addResource
(
DEFAULT_LIBRARY
);
}
sResourceExtractor
.
start
();
}
public
static
void
onResume
(
Context
context
)
{
if
(
sResourceUpdater
!=
null
)
{
if
(
sResourceUpdater
.
getDownloadMode
()
==
ResourceUpdater
.
DownloadMode
.
ON_RESUME
)
{
sResourceUpdater
.
startUpdateDownloadOnce
();
}
}
}
/**
* Returns a list of the file names at the root of the application's asset
* path.
...
...
@@ -403,15 +364,6 @@ public class FlutterMain {
return
appBundle
.
exists
()
?
appBundle
.
getPath
()
:
null
;
}
/**
* Returns the main internal interface for the dynamic patching subsystem.
*
* If this is null, it means that dynamic patching is disabled in this app.
*/
public
static
ResourceUpdater
getResourceUpdater
()
{
return
sResourceUpdater
;
}
/**
* Returns the file name for the given asset.
* The returned file name can be used to access the asset in the APK
...
...
shell/platform/android/io/flutter/view/ResourceExtractor.java
浏览文件 @
8b5f7763
...
...
@@ -52,64 +52,26 @@ class ResourceExtractor {
protected
Void
doInBackground
(
Void
...
unused
)
{
final
File
dataDir
=
new
File
(
PathUtils
.
getDataDirectory
(
mContext
));
ResourceUpdater
resourceUpdater
=
FlutterMain
.
getResourceUpdater
();
if
(
resourceUpdater
!=
null
)
{
// Protect patch file from being overwritten by downloader while
// it's being extracted since downloading happens asynchronously.
resourceUpdater
.
getInstallationLock
().
lock
();
final
String
timestamp
=
checkTimestamp
(
dataDir
);
if
(
timestamp
==
null
)
{
return
null
;
}
try
{
if
(
resourceUpdater
!=
null
)
{
File
updateFile
=
resourceUpdater
.
getDownloadedPatch
();
File
activeFile
=
resourceUpdater
.
getInstalledPatch
();
if
(
updateFile
.
exists
())
{
JSONObject
manifest
=
resourceUpdater
.
readManifest
(
updateFile
);
if
(
resourceUpdater
.
validateManifest
(
manifest
))
{
// Graduate patch file as active for asset manager.
if
(
activeFile
.
exists
()
&&
!
activeFile
.
delete
())
{
Log
.
w
(
TAG
,
"Could not delete file "
+
activeFile
);
return
null
;
}
if
(!
updateFile
.
renameTo
(
activeFile
))
{
Log
.
w
(
TAG
,
"Could not create file "
+
activeFile
);
return
null
;
}
}
}
}
final
String
timestamp
=
checkTimestamp
(
dataDir
);
if
(
timestamp
==
null
)
{
return
null
;
}
deleteFiles
();
if
(!
extractUpdate
(
dataDir
))
{
return
null
;
}
deleteFiles
();
if
(!
extractAPK
(
dataDir
))
{
return
null
;
}
if
(!
extractAPK
(
dataDir
))
{
return
null
;
}
if
(
timestamp
!=
null
)
{
try
{
new
File
(
dataDir
,
timestamp
).
createNewFile
();
}
catch
(
IOException
e
)
{
Log
.
w
(
TAG
,
"Failed to write resource timestamp"
);
}
if
(
timestamp
!=
null
)
{
try
{
new
File
(
dataDir
,
timestamp
).
createNewFile
();
}
catch
(
IOException
e
)
{
Log
.
w
(
TAG
,
"Failed to write resource timestamp"
);
}
}
return
null
;
}
finally
{
if
(
resourceUpdater
!=
null
)
{
resourceUpdater
.
getInstallationLock
().
unlock
();
}
}
return
null
;
}
}
...
...
@@ -213,133 +175,6 @@ class ResourceExtractor {
return
true
;
}
/// 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
;
}
File
updateFile
=
resourceUpdater
.
getInstalledPatch
();
if
(!
updateFile
.
exists
())
{
return
true
;
}
JSONObject
manifest
=
resourceUpdater
.
readManifest
(
updateFile
);
if
(!
resourceUpdater
.
validateManifest
(
manifest
))
{
// Obsolete patch file, nothing to install.
return
true
;
}
ZipFile
zipFile
;
try
{
zipFile
=
new
ZipFile
(
updateFile
);
}
catch
(
IOException
e
)
{
Log
.
w
(
TAG
,
"Exception unpacking resources: "
+
e
.
getMessage
());
deleteFiles
();
return
false
;
}
for
(
String
asset
:
mResources
)
{
String
resource
=
null
;
ZipEntry
entry
=
null
;
if
(
asset
.
endsWith
(
".so"
))
{
// Replicate library lookup logic.
for
(
String
abi
:
SUPPORTED_ABIS
)
{
resource
=
"lib/"
+
abi
+
"/"
+
asset
;
entry
=
zipFile
.
getEntry
(
resource
);
if
(
entry
==
null
)
{
entry
=
zipFile
.
getEntry
(
resource
+
".bzdiff40"
);
if
(
entry
==
null
)
{
continue
;
}
}
// Stop after the first match.
break
;
}
}
if
(
entry
==
null
)
{
resource
=
"assets/"
+
asset
;
entry
=
zipFile
.
getEntry
(
resource
);
if
(
entry
==
null
)
{
entry
=
zipFile
.
getEntry
(
resource
+
".bzdiff40"
);
if
(
entry
==
null
)
{
continue
;
}
}
}
final
File
output
=
new
File
(
dataDir
,
asset
);
if
(
output
.
exists
())
{
continue
;
}
if
(
output
.
getParentFile
()
!=
null
)
{
output
.
getParentFile
().
mkdirs
();
}
try
{
if
(
entry
.
getName
().
endsWith
(
".bzdiff40"
))
{
ByteArrayOutputStream
diff
=
new
ByteArrayOutputStream
();
try
(
InputStream
is
=
zipFile
.
getInputStream
(
entry
))
{
copy
(
is
,
diff
);
}
ByteArrayOutputStream
orig
=
new
ByteArrayOutputStream
();
if
(
asset
.
endsWith
(
".so"
))
{
ZipFile
apkFile
=
new
ZipFile
(
getAPKPath
());
if
(
apkFile
==
null
)
{
throw
new
IOException
(
"Could not find APK"
);
}
ZipEntry
origEntry
=
apkFile
.
getEntry
(
resource
);
if
(
origEntry
==
null
)
{
throw
new
IOException
(
"Could not find APK resource "
+
resource
);
}
try
(
InputStream
is
=
apkFile
.
getInputStream
(
origEntry
))
{
copy
(
is
,
orig
);
}
}
else
{
try
(
InputStream
is
=
manager
.
open
(
asset
))
{
copy
(
is
,
orig
);
}
catch
(
FileNotFoundException
e
)
{
throw
new
IOException
(
"Could not find APK resource "
+
resource
);
}
}
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
);
}
}
Log
.
i
(
TAG
,
"Extracted override resource "
+
entry
.
getName
());
}
catch
(
FileNotFoundException
fnfe
)
{
continue
;
}
catch
(
IOException
ioe
)
{
Log
.
w
(
TAG
,
"Exception unpacking resources: "
+
ioe
.
getMessage
());
deleteFiles
();
return
false
;
}
}
return
true
;
}
// Returns null if extracted resources are found and match the current APK version
// and update version if any, otherwise returns the current APK and update version.
private
String
checkTimestamp
(
File
dataDir
)
{
...
...
@@ -359,20 +194,6 @@ class ResourceExtractor {
String
expectedTimestamp
=
TIMESTAMP_PREFIX
+
getVersionCode
(
packageInfo
)
+
"-"
+
packageInfo
.
lastUpdateTime
;
ResourceUpdater
resourceUpdater
=
FlutterMain
.
getResourceUpdater
();
if
(
resourceUpdater
!=
null
)
{
File
patchFile
=
resourceUpdater
.
getInstalledPatch
();
JSONObject
manifest
=
resourceUpdater
.
readManifest
(
patchFile
);
if
(
resourceUpdater
.
validateManifest
(
manifest
))
{
String
patchNumber
=
manifest
.
optString
(
"patchNumber"
,
null
);
if
(
patchNumber
!=
null
)
{
expectedTimestamp
+=
"-"
+
patchNumber
+
"-"
+
patchFile
.
lastModified
();
}
else
{
expectedTimestamp
+=
"-"
+
patchFile
.
lastModified
();
}
}
}
final
String
[]
existingTimestamps
=
getExistingTimestamps
(
dataDir
);
if
(
existingTimestamps
==
null
)
{
...
...
shell/platform/android/io/flutter/view/ResourceUpdater.java
已删除
100644 → 0
浏览文件 @
1bcb96bf
// Copyright 2013 The Flutter Authors. 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.view
;
import
android.content.Context
;
import
android.content.pm.PackageInfo
;
import
android.content.pm.PackageManager
;
import
android.content.res.AssetManager
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
import
android.util.Log
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.InputStream
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.lang.Math
;
import
java.net.HttpURLConnection
;
import
java.net.URI
;
import
java.net.URISyntaxException
;
import
java.net.URL
;
import
java.util.Date
;
import
java.util.Scanner
;
import
java.util.concurrent.CancellationException
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.locks.Lock
;
import
java.util.concurrent.locks.ReentrantLock
;
import
java.util.zip.CRC32
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
public
final
class
ResourceUpdater
{
private
static
final
String
TAG
=
"ResourceUpdater"
;
private
static
final
int
BUFFER_SIZE
=
16
*
1024
;
// Controls when to check if a new patch is available for download, and start downloading.
// Note that by default the application will not block to wait for the download to finish.
// Patches are downloaded in the background, but the developer can also use [InstallMode]
// to control whether to block on download completion, in order to install patches sooner.
enum
DownloadMode
{
// Check for and download patch on application restart (but not necessarily apply it).
// This is the default setting which will also check for new patches least frequently.
ON_RESTART
,
// Check for and download patch on application resume (but not necessarily apply it).
// By definition, this setting will check for new patches both on restart and resume.
ON_RESUME
}
// Controls when to check that a new patch has been downloaded and needs to be applied.
enum
InstallMode
{
// Wait for next application restart before applying downloaded patch. With this
// setting, the application will not block to wait for patch download to finish.
// The application can be restarted later either by the user, or by the system,
// for any reason, at which point the newly downloaded patch will get applied.
// This is the default setting, and is the least disruptive way to apply patches.
ON_NEXT_RESTART
,
// Apply patch as soon as it's downloaded. This will block to wait for new patch
// download to finish, and will immediately apply it. This setting increases the
// urgency with which patches are installed, but may also affect startup latency.
// For now, this setting is only effective when download happens during restart.
// Patches downloaded during resume will not get installed immediately as that
// requires force restarting the app (which might be implemented in the future).
IMMEDIATE
}
/// Lock that prevents replacement of the install file by the downloader
/// while this file is being extracted, since these can happen in parallel.
Lock
getInstallationLock
()
{
return
installationLock
;
}
// Patch file that's fully installed and is ready to serve assets.
// This file represents the final stage in the installation process.
public
File
getInstalledPatch
()
{
return
new
File
(
context
.
getFilesDir
().
toString
()
+
"/patch.zip"
);
}
// Patch file that's finished downloading and is ready to be installed.
// This is a separate file in order to prevent serving assets from patch
// that failed installing for any reason, such as mismatched APK version.
File
getDownloadedPatch
()
{
return
new
File
(
getInstalledPatch
().
getPath
()
+
".install"
);
}
private
class
DownloadTask
extends
AsyncTask
<
String
,
String
,
Void
>
{
@Override
protected
Void
doInBackground
(
String
...
unused
)
{
try
{
URL
unresolvedURL
=
new
URL
(
buildUpdateDownloadURL
());
// Download to transient file to avoid extracting incomplete download.
File
localFile
=
new
File
(
getInstalledPatch
().
getPath
()
+
".download"
);
long
startMillis
=
new
Date
().
getTime
();
Log
.
i
(
TAG
,
"Checking for updates at "
+
unresolvedURL
);
HttpURLConnection
connection
=
(
HttpURLConnection
)
unresolvedURL
.
openConnection
();
long
lastDownloadTime
=
Math
.
max
(
getDownloadedPatch
().
lastModified
(),
getInstalledPatch
().
lastModified
());
if
(
lastDownloadTime
!=
0
)
{
Log
.
i
(
TAG
,
"Active update timestamp "
+
lastDownloadTime
);
connection
.
setIfModifiedSince
(
lastDownloadTime
);
}
URL
resolvedURL
=
connection
.
getURL
();
Log
.
i
(
TAG
,
"Resolved update URL "
+
resolvedURL
);
int
responseCode
=
connection
.
getResponseCode
();
Log
.
i
(
TAG
,
"HTTP response code "
+
responseCode
);
if
(
responseCode
==
HttpURLConnection
.
HTTP_NOT_FOUND
)
{
Log
.
i
(
TAG
,
"Latest update not found on server"
);
return
null
;
}
if
(
responseCode
==
HttpURLConnection
.
HTTP_NOT_MODIFIED
)
{
Log
.
i
(
TAG
,
"Already have latest update"
);
return
null
;
}
try
(
InputStream
input
=
connection
.
getInputStream
())
{
Log
.
i
(
TAG
,
"Downloading update "
+
unresolvedURL
);
try
(
OutputStream
output
=
new
FileOutputStream
(
localFile
))
{
int
count
;
byte
[]
data
=
new
byte
[
1024
];
while
((
count
=
input
.
read
(
data
))
!=
-
1
)
{
output
.
write
(
data
,
0
,
count
);
}
long
totalMillis
=
new
Date
().
getTime
()
-
startMillis
;
Log
.
i
(
TAG
,
"Update downloaded in "
+
totalMillis
/
100
/
10
.
+
"s"
);
}
}
// Wait renaming the file if extraction is in progress.
installationLock
.
lock
();
try
{
File
updateFile
=
getDownloadedPatch
();
// Graduate downloaded file as ready for installation.
if
(
updateFile
.
exists
()
&&
!
updateFile
.
delete
())
{
Log
.
w
(
TAG
,
"Could not delete file "
+
updateFile
);
return
null
;
}
if
(!
localFile
.
renameTo
(
updateFile
))
{
Log
.
w
(
TAG
,
"Could not create file "
+
updateFile
);
return
null
;
}
return
null
;
}
finally
{
installationLock
.
unlock
();
}
}
catch
(
IOException
e
)
{
Log
.
w
(
TAG
,
"Could not download update "
+
e
.
getMessage
());
return
null
;
}
}
}
private
final
Context
context
;
private
DownloadTask
downloadTask
;
private
final
Lock
installationLock
=
new
ReentrantLock
();
public
ResourceUpdater
(
Context
context
)
{
this
.
context
=
context
;
}
private
String
getAPKVersion
()
{
try
{
PackageManager
packageManager
=
context
.
getPackageManager
();
PackageInfo
packageInfo
=
packageManager
.
getPackageInfo
(
context
.
getPackageName
(),
0
);
return
packageInfo
==
null
?
null
:
Long
.
toString
(
ResourceExtractor
.
getVersionCode
(
packageInfo
));
}
catch
(
PackageManager
.
NameNotFoundException
e
)
{
return
null
;
}
}
private
String
buildUpdateDownloadURL
()
{
Bundle
metaData
;
try
{
metaData
=
context
.
getPackageManager
().
getApplicationInfo
(
context
.
getPackageName
(),
PackageManager
.
GET_META_DATA
).
metaData
;
}
catch
(
PackageManager
.
NameNotFoundException
e
)
{
throw
new
RuntimeException
(
e
);
}
if
(
metaData
==
null
||
metaData
.
getString
(
"PatchServerURL"
)
==
null
)
{
return
null
;
}
URI
uri
;
try
{
uri
=
new
URI
(
metaData
.
getString
(
"PatchServerURL"
)
+
"/"
+
getAPKVersion
()
+
".zip"
);
}
catch
(
URISyntaxException
e
)
{
Log
.
w
(
TAG
,
"Invalid AndroidManifest.xml PatchServerURL: "
+
e
.
getMessage
());
return
null
;
}
return
uri
.
normalize
().
toString
();
}
DownloadMode
getDownloadMode
()
{
Bundle
metaData
;
try
{
metaData
=
context
.
getPackageManager
().
getApplicationInfo
(
context
.
getPackageName
(),
PackageManager
.
GET_META_DATA
).
metaData
;
}
catch
(
PackageManager
.
NameNotFoundException
e
)
{
throw
new
RuntimeException
(
e
);
}
if
(
metaData
==
null
)
{
return
DownloadMode
.
ON_RESTART
;
}
String
patchDownloadMode
=
metaData
.
getString
(
"PatchDownloadMode"
);
if
(
patchDownloadMode
==
null
)
{
return
DownloadMode
.
ON_RESTART
;
}
try
{
return
DownloadMode
.
valueOf
(
patchDownloadMode
);
}
catch
(
IllegalArgumentException
e
)
{
Log
.
e
(
TAG
,
"Invalid PatchDownloadMode "
+
patchDownloadMode
);
return
DownloadMode
.
ON_RESTART
;
}
}
InstallMode
getInstallMode
()
{
Bundle
metaData
;
try
{
metaData
=
context
.
getPackageManager
().
getApplicationInfo
(
context
.
getPackageName
(),
PackageManager
.
GET_META_DATA
).
metaData
;
}
catch
(
PackageManager
.
NameNotFoundException
e
)
{
throw
new
RuntimeException
(
e
);
}
if
(
metaData
==
null
)
{
return
InstallMode
.
ON_NEXT_RESTART
;
}
String
patchInstallMode
=
metaData
.
getString
(
"PatchInstallMode"
);
if
(
patchInstallMode
==
null
)
{
return
InstallMode
.
ON_NEXT_RESTART
;
}
try
{
return
InstallMode
.
valueOf
(
patchInstallMode
);
}
catch
(
IllegalArgumentException
e
)
{
Log
.
e
(
TAG
,
"Invalid PatchInstallMode "
+
patchInstallMode
);
return
InstallMode
.
ON_NEXT_RESTART
;
}
}
/// Returns manifest JSON from ZIP file, or null if not found.
public
JSONObject
readManifest
(
File
updateFile
)
{
if
(!
updateFile
.
exists
())
{
return
null
;
}
try
{
ZipFile
zipFile
=
new
ZipFile
(
updateFile
);
ZipEntry
entry
=
zipFile
.
getEntry
(
"manifest.json"
);
if
(
entry
==
null
)
{
Log
.
w
(
TAG
,
"Invalid update file: "
+
updateFile
);
return
null
;
}
// Read and parse the entire JSON file as single operation.
Scanner
scanner
=
new
Scanner
(
zipFile
.
getInputStream
(
entry
));
return
new
JSONObject
(
scanner
.
useDelimiter
(
"\\A"
).
next
());
}
catch
(
IOException
|
JSONException
e
)
{
Log
.
w
(
TAG
,
"Invalid update file: "
+
e
);
return
null
;
}
}
/// Returns true if the patch file was indeed built for this APK.
public
boolean
validateManifest
(
JSONObject
manifest
)
{
if
(
manifest
==
null
)
{
return
false
;
}
String
buildNumber
=
manifest
.
optString
(
"buildNumber"
,
null
);
if
(
buildNumber
==
null
)
{
Log
.
w
(
TAG
,
"Invalid update manifest: missing buildNumber"
);
return
false
;
}
if
(!
buildNumber
.
equals
(
getAPKVersion
()))
{
Log
.
w
(
TAG
,
"Outdated update file for build "
+
getAPKVersion
());
return
false
;
}
String
baselineChecksum
=
manifest
.
optString
(
"baselineChecksum"
,
null
);
if
(
baselineChecksum
==
null
)
{
Log
.
w
(
TAG
,
"Invalid update manifest: missing baselineChecksum"
);
return
false
;
}
CRC32
checksum
=
new
CRC32
();
String
[]
checksumFiles
=
{
"isolate_snapshot_data"
,
"isolate_snapshot_instr"
,
"flutter_assets/isolate_snapshot_data"
,
};
for
(
String
fn
:
checksumFiles
)
{
AssetManager
manager
=
context
.
getResources
().
getAssets
();
try
(
InputStream
is
=
manager
.
open
(
fn
))
{
int
count
=
0
;
byte
[]
buffer
=
new
byte
[
BUFFER_SIZE
];
while
((
count
=
is
.
read
(
buffer
,
0
,
BUFFER_SIZE
))
!=
-
1
)
{
checksum
.
update
(
buffer
,
0
,
count
);
}
}
catch
(
IOException
e
)
{
// Skip missing files.
}
}
if
(!
baselineChecksum
.
equals
(
String
.
valueOf
(
checksum
.
getValue
())))
{
Log
.
w
(
TAG
,
"Mismatched update file for APK"
);
return
false
;
}
return
true
;
}
void
startUpdateDownloadOnce
()
{
if
(
downloadTask
!=
null
)
{
return
;
}
downloadTask
=
new
DownloadTask
();
downloadTask
.
executeOnExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
);
}
void
waitForDownloadCompletion
()
{
if
(
downloadTask
==
null
)
{
return
;
}
try
{
downloadTask
.
get
();
downloadTask
=
null
;
}
catch
(
CancellationException
e
)
{
Log
.
w
(
TAG
,
"Download cancelled: "
+
e
.
getMessage
());
return
;
}
catch
(
ExecutionException
e
)
{
Log
.
w
(
TAG
,
"Download exception: "
+
e
.
getMessage
());
return
;
}
catch
(
InterruptedException
e
)
{
Log
.
w
(
TAG
,
"Download interrupted: "
+
e
.
getMessage
());
return
;
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录