Skip to content

Commit af129b1

Browse files
authored
Merge pull request #271 from shamanec/feature/add-kill-apps-option
Enhance device apps obtaining logic and add option to kill apps from web UI
2 parents 8f723d1 + 74e8fea commit af129b1

9 files changed

Lines changed: 377 additions & 23 deletions

File tree

common/constants/constants.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,3 +803,24 @@ var IOSDeviceInfoMap = map[string]models.IOSModelData{
803803
Model: "iPad Pro 11-inch (M5) WiFi + Cellular",
804804
},
805805
}
806+
807+
// List of iOS system app bundle identifiers
808+
// Used mostly to add them to the list of installed apps for iOS devices
809+
// To be able to kill those apps from the UI
810+
var IOSSystemAppsBundleIds = []string{
811+
"com.apple.AppStore",
812+
"com.apple.camera",
813+
"com.apple.clips",
814+
"com.apple.compass",
815+
"com.apple.MobileAddressBook",
816+
"com.apple.facetime",
817+
"com.apple.DocumentsApp",
818+
"com.apple.Home",
819+
"com.apple.iMovie",
820+
"com.apple.mobilemail",
821+
"com.apple.Maps",
822+
"com.apple.Music",
823+
"com.apple.mobilenotes",
824+
"com.apple.mobilesafari",
825+
"com.apple.Preferences",
826+
}

common/models/models.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,3 +382,14 @@ func ValidateDevice(device *Device) error {
382382

383383
return nil
384384
}
385+
386+
type RunningApp struct {
387+
AppName string `json:"app_name" bson:"-"`
388+
BundleIdentifier string `json:"bundle_identifier" bson:"-"`
389+
}
390+
391+
type DeviceApp struct {
392+
AppName string `json:"app_name" bson:"-"`
393+
BundleIdentifier string `json:"bundle_identifier" bson:"-"`
394+
CanUninstall bool `json:"can_uninstall" bson:"-"`
395+
}

hub-ui

provider/devices/android.go

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ import (
2020
"bufio"
2121
"bytes"
2222
"context"
23+
"encoding/json"
2324
"fmt"
25+
"io"
26+
"net/http"
2427
"net/url"
2528
"os"
2629
"os/exec"
@@ -34,6 +37,20 @@ import (
3437
"github.com/gobwas/ws/wsutil"
3538
)
3639

40+
var remoteServerNetClient = &http.Client{
41+
Timeout: time.Second * 120,
42+
}
43+
44+
func androidRemoteServerRequest(device *models.Device, method, endpoint string, requestBody io.Reader) (*http.Response, error) {
45+
url := fmt.Sprintf("http://localhost:%s/%s", device.AndroidRemoteServerPort, endpoint)
46+
device.Logger.LogDebug("androidRemoteServerRequest", fmt.Sprintf("Calling `%s` for device `%s`", url, device.UDID))
47+
req, err := http.NewRequest(method, url, requestBody)
48+
if err != nil {
49+
return nil, err
50+
}
51+
return remoteServerNetClient.Do(req)
52+
}
53+
3754
// Check if the GADS-stream service is running on the device
3855
func isGadsStreamServiceRunning(device *models.Device) (bool, error) {
3956
logger.ProviderLogger.LogInfo("android_device_setup", fmt.Sprintf("Checking if GADS-stream is already running on device `%v`", device.UDID))
@@ -328,8 +345,8 @@ func updateAndroidScreenSizeADB(device *models.Device) error {
328345
return nil
329346
}
330347

331-
// Get all installed apps on an Android device
332-
func GetInstalledAppsAndroid(device *models.Device) []string {
348+
// Get all installed apps on an Android device - returns only the bundle identifiers (package names)
349+
func GetInstalledAppsBundleIdentifiersAndroid(device *models.Device) []string {
333350
installedApps := make([]string, 0)
334351
cmd := exec.CommandContext(device.Context, "adb", "-s", device.UDID, "shell", "cmd", "package", "list", "packages", "-3")
335352

@@ -359,6 +376,33 @@ func GetInstalledAppsAndroid(device *models.Device) []string {
359376
return installedApps
360377
}
361378

379+
// Get all installed apps on an Android device
380+
func GetInstalledAppsAndroidRemoteServer(device *models.Device) []models.DeviceApp {
381+
var deviceApps = make([]models.DeviceApp, 0)
382+
var err error
383+
384+
runningAppsResp, err := androidRemoteServerRequest(device, http.MethodGet, "installed-apps", nil)
385+
if err != nil {
386+
device.Logger.LogError("get_installed_apps", fmt.Sprintf("GetInstalledAppsAndroidRemoteServer: Failed executing remote server request - %s", err.Error()))
387+
fmt.Println("error in running apps resp - " + err.Error())
388+
return deviceApps
389+
}
390+
defer runningAppsResp.Body.Close()
391+
392+
payload, err := io.ReadAll(runningAppsResp.Body)
393+
if err != nil {
394+
device.Logger.LogError("get_installed_apps", fmt.Sprintf("GetInstalledAppsAndroidRemoteServer: Failed executing reading remote server response body - %s", err.Error()))
395+
return deviceApps
396+
}
397+
err = json.Unmarshal(payload, &deviceApps)
398+
if err != nil {
399+
device.Logger.LogError("get_installed_apps", fmt.Sprintf("GetInstalledAppsAndroidRemoteServer: Failed unmarshalling remote server response - %s", err.Error()))
400+
return deviceApps
401+
}
402+
403+
return deviceApps
404+
}
405+
362406
// Uninstall app from Android device by package name
363407
func uninstallAppAndroid(device *models.Device, packageName string) error {
364408
cmd := exec.CommandContext(device.Context, "adb", "-s", device.UDID, "uninstall", packageName)
@@ -660,3 +704,13 @@ func addAndroidSharedStorageFilePathNode(root *models.AndroidFileNode, fullPath
660704
current = child
661705
}
662706
}
707+
708+
func KillAppAndroid(device *models.Device, bundleIdentifier string) error {
709+
cmd := exec.CommandContext(device.Context, "adb", "-s", device.UDID, "shell", "am", "force-stop", bundleIdentifier)
710+
711+
if err := cmd.Run(); err != nil {
712+
return fmt.Errorf("KillAppAndroid: Failed killing app with bundle identifier(package name) `%s` via adb shell", bundleIdentifier)
713+
}
714+
715+
return nil
716+
}

provider/devices/common.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ func setupAndroidDevice(device *models.Device) {
415415

416416
// Get the currently installed appes on the device
417417
logger.ProviderLogger.LogDebug("android_device_setup", fmt.Sprintf("Checking for existing GADS Android apps on device `%v`", device.UDID))
418-
device.InstalledApps = GetInstalledAppsAndroid(device)
418+
device.InstalledApps = GetInstalledAppsBundleIdentifiersAndroid(device)
419419
logger.ProviderLogger.LogDebug("android_device_setup", fmt.Sprintf("Updated installed apps for Android device `%v`", device.UDID))
420420
// Uninstall the GADS-Settings app if present
421421
if slices.Contains(device.InstalledApps, "com.gads.settings") {
@@ -949,7 +949,7 @@ func setupIOSDevice(device *models.Device) {
949949
}
950950
}
951951

952-
device.InstalledApps = GetInstalledAppsIOS(device)
952+
device.InstalledApps = GetInstalledAppsBundleIdentifiersIOS(device)
953953
logger.ProviderLogger.LogDebug("ios_device_setup", fmt.Sprintf("Updated installed apps for device `%v`", device.UDID))
954954

955955
// Mark the device as 'live'
@@ -1263,9 +1263,9 @@ func startGridNode(device *models.Device) {
12631263

12641264
func UpdateInstalledApps(device *models.Device) {
12651265
if device.OS == "ios" {
1266-
device.InstalledApps = GetInstalledAppsIOS(device)
1266+
device.InstalledApps = GetInstalledAppsBundleIdentifiersIOS(device)
12671267
} else {
1268-
device.InstalledApps = GetInstalledAppsAndroid(device)
1268+
device.InstalledApps = GetInstalledAppsBundleIdentifiersAndroid(device)
12691269
}
12701270
}
12711271

@@ -1291,25 +1291,26 @@ func UninstallApp(device *models.Device, app string) error {
12911291
}
12921292

12931293
func InstallApp(device *models.Device, app string) error {
1294-
if device.OS == "ios" {
1294+
switch device.OS {
1295+
case "ios":
12951296
err := installAppDefaultPath(device, app)
12961297
if err != nil {
12971298
device.Logger.LogError("install_app_ios", fmt.Sprintf("Failed installing app on device `%s` - %s", device.UDID, err))
12981299
return err
12991300
}
1300-
} else if device.OS == "android" {
1301+
case "android":
13011302
err := installAppAndroid(device, app)
13021303
if err != nil {
13031304
device.Logger.LogError("install_app_android", fmt.Sprintf("Failed installing app on device `%s` - %s", device.UDID, err))
13041305
return err
13051306
}
1306-
} else if device.OS == "tizen" {
1307+
case "tizen":
13071308
err := installAppTizen(device, app)
13081309
if err != nil {
13091310
device.Logger.LogError("install_app_tizen", fmt.Sprintf("Failed installing app on device `%s` - %s", device.UDID, err))
13101311
return err
13111312
}
1312-
} else if device.OS == "webos" {
1313+
case "webos":
13131314
err := installAppWebOS(device, app)
13141315
if err != nil {
13151316
device.Logger.LogError("install_app_webos", fmt.Sprintf("Failed installing app on device `%s` - %s", device.UDID, err))

0 commit comments

Comments
 (0)