Skip to content

Commit

Permalink
v2.6.3
Browse files Browse the repository at this point in the history
Fixing the latest batch of nasty low level issues.
* Handle different `SIGSYS` event ordering on armhf devices running a newer version of Android.  People would have seen this as being stuck at the end of extraction.
* Handle `waitpid` being blocked.  Would show up as infinite spinning at the starting service stage on some devices/versions of Android.
* Handle `sendmmsg` being block on some intel/amd devices.
* Handle some devices (Leveno Yogabook, any others?) using a different set of libraries than advertised in `Build.SUPPORTED_ABIS`
* Fix port number issue introduced recently.  Was having trouble finding the pid files before.
  • Loading branch information
corbinlc authored Sep 5, 2019
2 parents 62a5679 + 25e8651 commit 566d783
Show file tree
Hide file tree
Showing 30 changed files with 175 additions and 150 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ reference:
android_config: &android_config
working_directory: *workspace
docker:
- image: circleci/android:api-28-ndk
- image: circleci/android@sha256:fa7a00c75f4b28cc4f2a15a382fb76e830d62a77efd1a3f8549f7f5fdad4ca44
environment:
TERM: dumb
# Limit JVM heap size to prevent exceeding container memory
Expand Down Expand Up @@ -345,4 +345,4 @@ workflows:
requires:
- test_unit
- test_instrumented
- build_production_release
- build_production_release
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ These are intended as just that: guidelines, so use your best judgement when sub
All contributions must follow the UserLAnd [Code of Conduct](https://github.com/CypherpunkArmory/UserLAnd/blob/master/CODE_OF_CONDUCT.md).

## Connect with us
If you have any questions please join us on our [slack](https://communityinviter.com/apps/userlandtech/userland) #contributors channel
Please talk with us here in the form of a PR or an issue.

## Architecture
We follow the MVVM-C architecture in UserLAnd. UI updates should exist exclusively within XML and be inflated exclusively from
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ Features:
* Install and uninstall like a regular app.
* No root required.

[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/tech.ula/)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/tech.ula)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=tech.ula)

## Have a bug report or a feature request?
You can see our templates by visiting our [issue center](https://github.com/CypherpunkArmory/UserLAnd/issues).

You can also chat with us on [slack](https://communityinviter.com/apps/userlandtech/userland).
## Want to contribute?
See our [CONTRIBUTING](https://github.com/CypherpunkArmory/UserLAnd/blob/master/CONTRIBUTING.md) document.

Expand Down
7 changes: 4 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ android {
minSdkVersion 21
targetSdkVersion 29
versionCode vcode
versionName "2.6.2"
versionName "2.6.3"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments clearPackageData: 'true'
Expand Down Expand Up @@ -198,7 +198,7 @@ ext.architectures = ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
ext.libDir = "$project.projectDir/src/main/jniLibs"

task downloadAssets(type: Download) {
def assetVersion = "v1.0.1"
def assetVersion = "v1.1.0"
def baseUrl = "https://github.com/CypherpunkArmory/UserLAnd-Assets-Support/releases/download/$assetVersion"
for (arch in architectures) {
src "$baseUrl/$arch-assets.zip"
Expand All @@ -222,6 +222,7 @@ task fetchAssets(dependsOn: downloadAssets) {
// Lib files must start with 'lib' and end with '.so.'
rename '(.*)', 'lib_$1.so'
}
new File("$libDir/$arch","lib_arch.so").text = "$arch"
}
}
}
Expand Down Expand Up @@ -280,7 +281,6 @@ dependencies {
def mockito_version = '2.23.0'
def mockito_kotlin_version = '2.1.0'
def core_testing_version = '2.0.0-beta01'
def espresso_version = '3.2.0'
def androidx_test_version = '1.2.0'
def androidx_test_ext_version = '1.1.0'

Expand All @@ -296,6 +296,7 @@ dependencies {
androidTestImplementation "androidx.test:rules:$androidx_test_version"
androidTestImplementation "androidx.test.ext:junit:$androidx_test_ext_version"
// Barista packages espresso-core and espresso-contrib
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0'
androidTestImplementation('com.schibsted.spain:barista:3.1.0') {
exclude group: 'com.android.support'
exclude group: 'org.jetbrains.kotlin'
Expand Down
64 changes: 60 additions & 4 deletions app/src/androidTest/java/tech/ula/ui/MainActivityTest.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package tech.ula.ui

import android.Manifest
import android.content.Intent
import android.net.Uri
import androidx.test.espresso.Espresso
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.* // ktlint-disable no-wildcard-imports
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule
import androidx.test.rule.GrantPermissionRule
import com.schibsted.spain.barista.assertion.BaristaListAssertions.assertDisplayedAtPosition
import com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertNotDisplayed
Expand All @@ -27,7 +31,7 @@ import java.io.File
class MainActivityTest {

@get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java)
val intentTestRule = IntentsTestRule(MainActivity::class.java)

// Permissions are granted automatically by firebase, so to keep parity we skip that step
// locally as well.
Expand All @@ -47,12 +51,12 @@ class MainActivityTest {

@Before
fun setup() {
activity = activityRule.activity
activity = intentTestRule.activity
homeDirectory = File(activity.filesDir, homeLocation)
}

@Test
fun testHappyPath() {
fun test_ssh_session_can_be_started() {
R.id.app_list_fragment.shortWaitForDisplay()

R.id.swipe_refresh.waitForRefresh(activity)
Expand Down Expand Up @@ -121,6 +125,58 @@ class MainActivityTest {
R.id.terminal_view.shortWaitForDisplay()
}

@Test
fun test_vnc_session_can_be_started() {
R.id.app_list_fragment.shortWaitForDisplay()

R.id.swipe_refresh.waitForRefresh(activity)

// Click alpine
assertDisplayedAtPosition(R.id.list_apps, 0, R.id.apps_name, appName)
clickListItem(R.id.list_apps, 0)

// Set filesystem credentials
R.string.filesystem_credentials_reasoning.waitForDisplay()
writeTo(R.id.text_input_username, username)
writeTo(R.id.text_input_password, sshPassword)
writeTo(R.id.text_input_vnc_password, vncPassword)
clickDialogPositiveButton()

// Set session type to vnc
R.string.prompt_app_connection_type_preference.shortWaitForDisplay()
clickRadioButtonItem(R.id.radio_apps_service_type_preference, R.id.vnc_radio_button)
clickDialogPositiveButton()

// Wait for progress dialog to complete
R.id.progress_bar_session_list.shortWaitForDisplay()
R.string.progress_downloading.longWaitForDisplay()
R.string.progress_copying_downloads.extraLongWaitForDisplay()
R.string.progress_verifying_assets.waitForDisplay()
R.string.progress_setting_up_filesystem.waitForDisplay()
R.string.progress_starting.longWaitForDisplay()
Thread.sleep(10000)

val clientIntent = Intent()
clientIntent.action = Intent.ACTION_VIEW
clientIntent.type = "application/vnd.vnc"
clientIntent.data = Uri.parse("vnc://127.0.0.1:5951/?VncUsername=$username&VncPassword=$vncPassword")
clientIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val packageManager = activity.packageManager
val activities = packageManager.queryIntentActivities(clientIntent, 0)
if (activities.size > 0) {
// Match case where bVNC is present, e.g. test is running on personal device
intended(hasAction(Intent.ACTION_VIEW))
intended(hasData(Uri.parse("vnc://127.0.0.1:5951/?VncUsername=$username&VncPassword=$vncPassword")))
intended(hasFlag(Intent.FLAG_ACTIVITY_NEW_TASK))
} else {
// Match case where bVNC is not present on device, e.g. firebase
val packageName = "com.iiordanov.freebVNC"
intended(hasAction(Intent.ACTION_VIEW))
intended(hasData(Uri.parse("market://details?id=$packageName")))
intended(hasFlag(Intent.FLAG_ACTIVITY_NEW_TASK))
}
}

private fun doHappyPathTestScript(): List<File> {
val startedFile = File(homeDirectory, "test.scriptStarted")
val updatedFile = File(homeDirectory, "test.apkUpdated")
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/java/tech/ula/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import kotlinx.coroutines.launch
import tech.ula.model.entities.App
import tech.ula.model.entities.ServiceType
import tech.ula.model.entities.Session
import tech.ula.model.remote.GithubApiClient
import tech.ula.model.repositories.AssetRepository
import tech.ula.model.repositories.UlaDatabase
import tech.ula.model.state.* // ktlint-disable no-wildcard-imports
Expand Down Expand Up @@ -117,7 +118,8 @@ class MainActivity : AppCompatActivity(), SessionListFragment.SessionSelection,
val ulaDatabase = UlaDatabase.getInstance(this)

val assetPreferences = AssetPreferences(this)
val assetRepository = AssetRepository(filesDir.path, assetPreferences)
val githubApiClient = GithubApiClient(ulaFiles)
val assetRepository = AssetRepository(filesDir.path, assetPreferences, githubApiClient)

val filesystemManager = FilesystemManager(ulaFiles, busyboxExecutor)
val storageCalculator = StorageCalculator(StatFs(filesDir.path))
Expand All @@ -126,7 +128,7 @@ class MainActivity : AppCompatActivity(), SessionListFragment.SessionSelection,
val downloadManagerWrapper = DownloadManagerWrapper(downloadManager)
val assetDownloader = AssetDownloader(assetPreferences, downloadManagerWrapper, ulaFiles)

val appsStartupFsm = AppsStartupFsm(ulaDatabase, filesystemManager)
val appsStartupFsm = AppsStartupFsm(ulaDatabase, filesystemManager, ulaFiles)
val sessionStartupFsm = SessionStartupFsm(ulaDatabase, assetRepository, filesystemManager, assetDownloader, storageCalculator)
ViewModelProviders.of(this, MainActivityViewModelFactory(appsStartupFsm, sessionStartupFsm))
.get(MainActivityViewModel::class.java)
Expand Down
29 changes: 19 additions & 10 deletions app/src/main/java/tech/ula/ServerService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import android.content.Intent
import android.net.Uri
import android.os.IBinder
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.* // ktlint-disable no-wildcard-imports
import tech.ula.model.entities.App
import tech.ula.model.entities.ServiceType
import tech.ula.model.repositories.UlaDatabase
import tech.ula.model.entities.Session
import tech.ula.utils.* // ktlint-disable no-wildcard-imports
import kotlin.coroutines.CoroutineContext

class ServerService : Service() {
class ServerService : Service(), CoroutineScope {

private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + job

companion object {
const val SERVER_SERVICE_RESULT: String = "tech.ula.ServerService.RESULT"
Expand Down Expand Up @@ -53,9 +55,8 @@ class ServerService : Service() {

when (intent?.getStringExtra("type")) {
"start" -> {
val coroutineScope = CoroutineScope(Dispatchers.Default)
val session: Session = intent.getParcelableExtra("session")!!
coroutineScope.launch { startSession(session) }
this.launch { startSession(session) }
}
"stopApp" -> {
val app: App = intent.getParcelableExtra("app")!!
Expand Down Expand Up @@ -87,10 +88,18 @@ class ServerService : Service() {
// to clean up when app is swiped away.
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
// Redundancy to ensure no hanging processes, given broad device spectrum.
this.coroutineContext.cancel()
stopForeground(true)
stopSelf()
}

override fun onDestroy() {
super.onDestroy()
// Redundancy to ensure no hanging processes, given broad device spectrum.
this.coroutineContext.cancel()
}

private fun removeSession(session: Session) {
activeSessions.remove(session.pid)
if (activeSessions.isEmpty()) {
Expand Down Expand Up @@ -145,16 +154,16 @@ class ServerService : Service() {

private fun startSshClient(session: Session) {
val connectBotIntent = Intent()
connectBotIntent.action = "android.intent.action.VIEW"
connectBotIntent.data = Uri.parse("ssh://${session.username}@localhost:${session.port}/#userland")
connectBotIntent.action = Intent.ACTION_VIEW
connectBotIntent.data = Uri.parse("ssh://${session.username}@localhost:2022/#userland")
connectBotIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

startActivity(connectBotIntent)
}

private fun startVncClient(session: Session, packageName: String) {
val bVncIntent = Intent()
bVncIntent.action = "android.intent.action.VIEW"
bVncIntent.action = Intent.ACTION_VIEW
bVncIntent.type = "application/vnd.vnc"
bVncIntent.data = Uri.parse("vnc://127.0.0.1:5951/?VncUsername=${session.username}&VncPassword=${session.vncPassword}")
bVncIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/tech/ula/model/entities/Session.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ data class Session(
var password: String = "",
var vncPassword: String = "",
var serviceType: ServiceType = ServiceType.Unselected,
var port: Long = 2022,
var port: Long = 2022, // TODO This can be removed. Any eventual port managing should be done at a high er abstraction.
var pid: Long = 0,
var geometry: String = "",
val isAppsSession: Boolean = false
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/tech/ula/model/remote/GithubApiClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import tech.ula.utils.DeviceArchitecture
import tech.ula.utils.Logger
import tech.ula.utils.SentryLogger
import tech.ula.utils.UlaFiles
import java.io.IOException
import java.net.UnknownHostException

Expand All @@ -20,7 +20,7 @@ class UrlProvider {
}

class GithubApiClient(
private val deviceArchitecture: DeviceArchitecture = DeviceArchitecture(),
private val ulaFiles: UlaFiles,
private val urlProvider: UrlProvider = UrlProvider(),
private val logger: Logger = SentryLogger()
) {
Expand All @@ -39,7 +39,7 @@ class GithubApiClient(
suspend fun getAssetsListDownloadUrl(repo: String): String = withContext(Dispatchers.IO) {
val result = latestResults[repo] ?: queryLatestRelease(repo)

return@withContext result.assets.find { it.name == "${deviceArchitecture.getArchType()}-assets.txt" }!!.downloadUrl
return@withContext result.assets.find { it.name == "${ulaFiles.getArchType()}-assets.txt" }!!.downloadUrl
}

@Throws(IOException::class)
Expand All @@ -52,7 +52,7 @@ class GithubApiClient(
@Throws(IOException::class)
suspend fun getAssetEndpoint(assetType: String, repo: String): String = withContext(Dispatchers.IO) {
val result = latestResults[repo] ?: queryLatestRelease(repo)
val assetName = "${deviceArchitecture.getArchType()}-$assetType"
val assetName = "${ulaFiles.getArchType()}-$assetType"

return@withContext result.assets.find { it.name == assetName }!!.downloadUrl
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ data class DownloadMetadata(
class AssetRepository(
private val applicationFilesDirPath: String,
private val assetPreferences: AssetPreferences,
private val githubApiClient: GithubApiClient = GithubApiClient(),
private val githubApiClient: GithubApiClient,
private val httpStream: HttpStream = HttpStream(),
private val logger: Logger = SentryLogger()
) {
Expand Down
6 changes: 2 additions & 4 deletions app/src/main/java/tech/ula/model/state/AppsStartupFsm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import tech.ula.utils.* // ktlint-disable no-wildcard-imports
class AppsStartupFsm(
ulaDatabase: UlaDatabase,
private val filesystemManager: FilesystemManager,
private val deviceArchitecture: DeviceArchitecture = DeviceArchitecture(),
private val ulaFiles: UlaFiles,
private val logger: Logger = SentryLogger()
) {

Expand Down Expand Up @@ -114,7 +114,6 @@ class AppsStartupFsm(

private suspend fun setServiceType(appSession: Session, serviceType: ServiceType) = withContext(Dispatchers.IO) {
appSession.serviceType = serviceType
appSession.port = if (serviceType == ServiceType.Ssh) 2022 else 51
sessionDao.updateSession(appSession)
state.postValue(AppHasServiceTypeSet)
}
Expand All @@ -124,7 +123,7 @@ class AppsStartupFsm(
val potentialAppFilesystem = filesystemDao.findAppsFilesystemByType(app.filesystemRequired)

if (potentialAppFilesystem.isEmpty()) {
val deviceArchitecture = deviceArchitecture.getArchType()
val deviceArchitecture = ulaFiles.getArchType()
val fsToInsert = Filesystem(0, name = "apps", archType = deviceArchitecture,
distributionType = app.filesystemRequired, isAppsFilesystem = true)
filesystemDao.insertFilesystem(fsToInsert)
Expand Down Expand Up @@ -157,7 +156,6 @@ class AppsStartupFsm(
state.postValue(SyncingDatabaseEntries)
appSession.filesystemId = appsFilesystem.id
appSession.filesystemName = appsFilesystem.name
appSession.port = if (appSession.serviceType is ServiceType.Ssh) 2022 else 51
appSession.username = appsFilesystem.defaultUsername
appSession.password = appsFilesystem.defaultPassword
appSession.vncPassword = appsFilesystem.defaultVncPassword
Expand Down
Loading

0 comments on commit 566d783

Please sign in to comment.