blob: 1a5b83289e5d3c1315b7c2faf049bdccdf5a4d4e [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:logging/logging.dart';
import 'component_search.dart';
import 'sl4f_client.dart';
final _log = Logger('modular');
/// The function type for making a generic request to Modular.
typedef ModularRequestFn = Future<dynamic> Function(String request,
[dynamic params]);
/// Allows controlling a Modular session and its components.
class Modular {
/// The function used to make a custom request for Modular.
final ModularRequestFn _request;
/// The handle to a component search query issuer.
final ComponentSearch _componentSearch;
bool _controlsBasemgr = false;
Modular(Sl4f sl4f, {ComponentSearch componentSearch})
: _request = sl4f.request,
_componentSearch = componentSearch ?? ComponentSearch(sl4f);
/// Restarts a Modular session.
///
/// This is equivalent to sessionctl restart_session.
Future<String> restartSession() async =>
await _request('basemgr_facade.RestartSession');
/// Kill Basemgr.
///
/// This is equivalent to basemgr_launcher shutdown.
Future<String> killBasemgr() async =>
await _request('basemgr_facade.KillBasemgr');
/// Launches Basemgr.
///
/// Takes a custom [config] as JSON serialized string, or launches basemgr
/// with system default config if not provided.
Future<String> startBasemgr([String config]) async {
if (config != null && config.isNotEmpty) {
return await _request(
'basemgr_facade.StartBasemgr', {'config': json.decode(config)});
} else {
return await _request('basemgr_facade.StartBasemgr', {});
}
}
/// Launches Mod.
///
/// Take custom parameters or launch mod with default value.
Future<String> launchMod(String modUrl,
{String modName,
String storyName,
bool focusMod,
bool focusStory}) async {
return await _request('basemgr_facade.LaunchMod', {
'mod_url': modUrl,
'mod_name': modName,
'story_name': storyName,
'focus_mod': focusMod,
'focus_story': focusStory
});
}
/// Whether basemgr is running on the DUT.
Future<bool> get isRunning => _componentSearch.search('basemgr.cmx');
/// Starts basemgr if it isn't running yet.
///
/// Takes a custom [config] as JSON serialized string, or launches basemgr
/// with system default config if not provided.
///
/// If [assumeControl] is true and basemgr wasn't running, then this object
/// will stop basemgr when [shutdown] is called with no arguments.
Future<void> boot({String config, bool assumeControl = false}) async {
if (await isRunning) {
_log.info('Not taking control of basemgr, it was already running.');
return;
}
_log.info('Booting basemgr with ${(config != null) ? 'custom' : 'default'} '
'configuration.');
await startBasemgr(config);
await Future.delayed(Duration(seconds: 10));
if (assumeControl) {
_controlsBasemgr = true;
}
}
/// Stops basemgr if it is controlled by this instance, or if
/// [forceShutdownBasemgr] is true.
Future<void> shutdown({bool forceShutdownBasemgr = false}) async {
if (!forceShutdownBasemgr && !_controlsBasemgr) {
_log.info(
'Modular SL4F client does not control basemgr, not shutting it down');
return;
}
if (!await isRunning) {
_log.info('Basemgr does not seem to be running before shutdown.');
// Running `basemgr_launcher shutdown` when basemgr is not running
// produces a very confusing stacktrace in the logs, so we avoid it here.
return;
}
_log.info('Shutting down basemgr.');
await killBasemgr();
// basemgr and all the agents can take some time to fully die.
await Future.delayed(Duration(seconds: 5));
_controlsBasemgr = false;
}
}