mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge pull request #991 from mpcomplete/update.service
Introduce an UpdateService for android
This commit is contained in:
commit
c780e0cb13
@ -15,5 +15,9 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service
|
||||
android:name="org.domokit.sky.shell.UpdateService"
|
||||
android:exported="false"
|
||||
android:process=":remote"/>
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@ -47,8 +47,11 @@ template("sky_app") {
|
||||
|
||||
sources = [
|
||||
"$root_build_dir/icudtl.dat",
|
||||
"$target_gen_dir/app.skyx",
|
||||
"$target_gen_dir/app.skyx"
|
||||
]
|
||||
if (defined(invoker.manifest)) {
|
||||
sources += [ invoker.manifest ]
|
||||
}
|
||||
deps = [
|
||||
":$skyx_target_name",
|
||||
":gen_${bundle_prefix}_bundle",
|
||||
|
||||
@ -90,6 +90,7 @@ if (is_android) {
|
||||
"android/org/domokit/sky/shell/PlatformViewAndroid.java",
|
||||
"android/org/domokit/sky/shell/SkyMain.java",
|
||||
"android/org/domokit/sky/shell/TracingController.java",
|
||||
"android/org/domokit/sky/shell/UpdateService.java",
|
||||
]
|
||||
jni_package = "sky/shell"
|
||||
}
|
||||
@ -105,6 +106,7 @@ if (is_android) {
|
||||
"android/sky_main.h",
|
||||
"android/tracing_controller.cc",
|
||||
"android/tracing_controller.h",
|
||||
"android/update_service_android.cc",
|
||||
]
|
||||
|
||||
deps = common_deps + [
|
||||
@ -131,6 +133,7 @@ if (is_android) {
|
||||
"android/org/domokit/sky/shell/SkyApplication.java",
|
||||
"android/org/domokit/sky/shell/SkyMain.java",
|
||||
"android/org/domokit/sky/shell/TracingController.java",
|
||||
"android/org/domokit/sky/shell/UpdateService.java",
|
||||
]
|
||||
|
||||
deps = [
|
||||
|
||||
@ -21,5 +21,9 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service
|
||||
android:name="UpdateService"
|
||||
android:exported="false"
|
||||
android:process=":remote"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include "sky/shell/android/platform_view_android.h"
|
||||
#include "sky/shell/android/sky_main.h"
|
||||
#include "sky/shell/android/tracing_controller.h"
|
||||
#include "sky/shell/android/update_service_android.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -25,6 +26,7 @@ base::android::RegistrationMethod kSkyRegisteredMethods[] = {
|
||||
{"PlatformViewAndroid", sky::shell::PlatformViewAndroid::Register},
|
||||
{"SkyMain", sky::shell::RegisterSkyMain},
|
||||
{"TracingController", sky::shell::RegisterTracingController},
|
||||
{"UpdateService", sky::shell::RegisterUpdateService},
|
||||
};
|
||||
|
||||
bool RegisterJNI(JNIEnv* env) {
|
||||
|
||||
@ -34,10 +34,11 @@ import org.domokit.vsync.VSyncProviderImpl;
|
||||
public class SkyApplication extends BaseChromiumApplication {
|
||||
static final String SNAPSHOT = "snapshot_blob.bin";
|
||||
static final String APP_BUNDLE = "app.skyx";
|
||||
static final String MANIFEST = "sky.yaml";
|
||||
|
||||
private static final String TAG = "SkyApplication";
|
||||
private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "sky_shell";
|
||||
private static final String[] SKY_RESOURCES = {"icudtl.dat", SNAPSHOT, APP_BUNDLE};
|
||||
private static final String[] SKY_RESOURCES = {"icudtl.dat", SNAPSHOT, APP_BUNDLE, MANIFEST};
|
||||
|
||||
private ResourceExtractor mResourceExtractor;
|
||||
|
||||
@ -51,6 +52,7 @@ public class SkyApplication extends BaseChromiumApplication {
|
||||
initJavaUtils();
|
||||
initResources();
|
||||
initNative();
|
||||
UpdateService.init(getApplicationContext());
|
||||
onServiceRegistryAvailable(ServiceRegistry.SHARED);
|
||||
}
|
||||
|
||||
|
||||
86
sky/shell/android/org/domokit/sky/shell/UpdateService.java
Normal file
86
sky/shell/android/org/domokit/sky/shell/UpdateService.java
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2015 The Chromium 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 org.domokit.sky.shell;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Service;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import java.io.File;
|
||||
import org.chromium.base.CalledByNative;
|
||||
import org.chromium.base.JNINamespace;
|
||||
import org.chromium.base.PathUtils;
|
||||
|
||||
/**
|
||||
* A class that schedules and runs periodic autoupdate checks.
|
||||
*/
|
||||
@JNINamespace("sky::shell")
|
||||
public class UpdateService extends Service {
|
||||
private static final String TAG = "UpdateService";
|
||||
private static final int REQUEST_CODE = 0; // Not sure why this is needed.
|
||||
private static final boolean ENABLED = false;
|
||||
|
||||
private long mNativePtr = 0;
|
||||
|
||||
public static void init(Context context) {
|
||||
if (ENABLED)
|
||||
maybeScheduleUpdateCheck(context);
|
||||
}
|
||||
|
||||
private static void maybeScheduleUpdateCheck(Context context) {
|
||||
Intent alarm = new Intent(context, UpdateService.class);
|
||||
PendingIntent existingIntent = PendingIntent.getService(
|
||||
context, REQUEST_CODE, alarm, PendingIntent.FLAG_NO_CREATE);
|
||||
if (existingIntent != null) {
|
||||
Log.i(TAG, "Update alarm exists: " + PathUtils.getDataDirectory(context));
|
||||
return;
|
||||
}
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getService(
|
||||
context, REQUEST_CODE, alarm, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
manager.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis(),
|
||||
AlarmManager.INTERVAL_DAY, pendingIntent);
|
||||
|
||||
Log.i(TAG, "Update scheduled: " + PathUtils.getDataDirectory(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
SkyMain.ensureInitialized(getApplicationContext(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mNativePtr != 0)
|
||||
nativeDetach(mNativePtr);
|
||||
mNativePtr = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
final File dataDir = new File(PathUtils.getDataDirectory(this));
|
||||
mNativePtr = nativeCheckForUpdates(dataDir.getPath());
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@CalledByNative
|
||||
public void onUpdateFinished() {
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
private native long nativeCheckForUpdates(String dataDir);
|
||||
private native void nativeDetach(long nativeUpdateTask);
|
||||
}
|
||||
118
sky/shell/android/update_service_android.cc
Normal file
118
sky/shell/android/update_service_android.cc
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sky/shell/android/update_service_android.h"
|
||||
|
||||
#include "base/android/jni_string.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "jni/UpdateService_jni.h"
|
||||
#include "mojo/data_pipe_utils/data_pipe_utils.h"
|
||||
#include "mojo/public/cpp/application/connect.h"
|
||||
#include "mojo/public/interfaces/application/service_provider.mojom.h"
|
||||
#include "mojo/services/network/public/interfaces/network_service.mojom.h"
|
||||
#include "sky/shell/shell.h"
|
||||
|
||||
namespace sky {
|
||||
namespace shell {
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(mpcomplete): make this a utility method?
|
||||
static mojo::URLLoaderPtr FetchURL(
|
||||
mojo::NetworkService* network_service,
|
||||
const std::string& url,
|
||||
base::Callback<void(mojo::URLResponsePtr)> callback) {
|
||||
mojo::URLLoaderPtr loader;
|
||||
network_service->CreateURLLoader(GetProxy(&loader));
|
||||
|
||||
mojo::URLRequestPtr request = mojo::URLRequest::New();
|
||||
request->url = url;
|
||||
request->auto_follow_redirects = true;
|
||||
loader->Start(request.Pass(), callback);
|
||||
|
||||
return loader.Pass();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static jlong CheckForUpdates(JNIEnv* env, jobject jcaller, jstring j_data_dir) {
|
||||
std::string data_dir = base::android::ConvertJavaStringToUTF8(env, j_data_dir);
|
||||
scoped_ptr<UpdateTask> task(new UpdateTask(env, jcaller, data_dir));
|
||||
|
||||
// TODO(mpcomplete): download a manifest and check the version.
|
||||
task->DownloadAppBundle("file://" + data_dir + "/app.skyx");
|
||||
|
||||
return reinterpret_cast<jlong>(task.release());
|
||||
}
|
||||
|
||||
bool RegisterUpdateService(JNIEnv* env) {
|
||||
return RegisterNativesImpl(env);
|
||||
}
|
||||
|
||||
UpdateTask::UpdateTask(JNIEnv* env, jobject update_service, std::string data_dir)
|
||||
: final_path_(base::FilePath(data_dir).AppendASCII("app.skyx")) {
|
||||
update_service_.Reset(env, update_service);
|
||||
|
||||
mojo::ServiceProviderPtr service_provider =
|
||||
CreateServiceProvider(Shell::Shared().service_provider_context());
|
||||
mojo::ConnectToService(service_provider.get(), &network_service_);
|
||||
}
|
||||
|
||||
void UpdateTask::DownloadAppBundle(const std::string& url) {
|
||||
LOG(INFO) << "Update downloading " << url << " to: " << final_path_.value();
|
||||
if (!base::CreateTemporaryFile(&temp_path_)) {
|
||||
CallOnFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
url_loader_ =
|
||||
FetchURL(network_service_.get(), url,
|
||||
base::Bind(&UpdateTask::OnResponse, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void UpdateTask::Detach(JNIEnv* env, jobject jcaller) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
void UpdateTask::OnResponse(mojo::URLResponsePtr response) {
|
||||
mojo::ScopedDataPipeConsumerHandle data;
|
||||
if (response->status_code == 200)
|
||||
data = response->body.Pass();
|
||||
if (!data.is_valid()) {
|
||||
LOG(ERROR) << "Update failed: Server responded " << response->status_code;
|
||||
CallOnFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_refptr<base::TaskRunner> worker_runner =
|
||||
base::WorkerPool::GetTaskRunner(true);
|
||||
mojo::common::CopyToFile(
|
||||
data.Pass(), temp_path_, worker_runner.get(),
|
||||
base::Bind(&UpdateTask::OnCopied, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void UpdateTask::OnCopied(bool success) {
|
||||
int64 size = 0;
|
||||
GetFileSize(temp_path_, &size);
|
||||
|
||||
// This assumes temp files are created on the same volume as the data_dir.
|
||||
// TODO(mpcomplete): only replace on next startup. Otherwise, a currently
|
||||
// running version of the app will get confused.
|
||||
bool rv = base::ReplaceFile(temp_path_, final_path_, nullptr);
|
||||
LOG(INFO) << "Update finished: " << rv << " filesize(" << final_path_.value() << ")=" << size;
|
||||
|
||||
CallOnFinished();
|
||||
}
|
||||
|
||||
void UpdateTask::CallOnFinished() {
|
||||
// The Java side is responsible for deleting the UpdateTask when finished.
|
||||
Java_UpdateService_onUpdateFinished(base::android::AttachCurrentThread(),
|
||||
update_service_.obj());
|
||||
}
|
||||
|
||||
} // namespace shell
|
||||
} // namespace sky
|
||||
41
sky/shell/android/update_service_android.h
Normal file
41
sky/shell/android/update_service_android.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SKY_SHELL_UPDATE_SERVICE_H_
|
||||
#define SKY_SHELL_UPDATE_SERVICE_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "base/android/jni_string.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "mojo/services/network/public/interfaces/network_service.mojom.h"
|
||||
|
||||
namespace sky {
|
||||
namespace shell {
|
||||
|
||||
class UpdateTask {
|
||||
public:
|
||||
UpdateTask(JNIEnv* env, jobject update_service, std::string data_dir);
|
||||
|
||||
void DownloadAppBundle(const std::string& url);
|
||||
void Detach(JNIEnv* env, jobject jcaller);
|
||||
|
||||
private:
|
||||
void OnResponse(mojo::URLResponsePtr response);
|
||||
void OnCopied(bool success);
|
||||
void CallOnFinished();
|
||||
|
||||
base::android::ScopedJavaGlobalRef<jobject> update_service_;
|
||||
mojo::NetworkServicePtr network_service_;
|
||||
base::FilePath temp_path_;
|
||||
base::FilePath final_path_;
|
||||
mojo::URLLoaderPtr url_loader_;
|
||||
};
|
||||
|
||||
bool RegisterUpdateService(JNIEnv* env);
|
||||
|
||||
} // namespace shell
|
||||
} // namespace sky
|
||||
|
||||
#endif // SKY_SHELL_UPDATE_SERVICE_H_
|
||||
Loading…
x
Reference in New Issue
Block a user