Compare commits

..

14 Commits

Author SHA1 Message Date
akwizgran
9ea4463cbc Avoid creating an in-memory copy of the log where possible.
This helps to avoid OOMs on low-memory devices.
2020-07-20 16:46:31 +01:00
akwizgran
a83682d4b6 Test that persistent log directory is deleted. 2020-07-14 11:29:14 +01:00
akwizgran
b1ec344bdb Update account manager test. 2020-07-14 11:28:33 +01:00
akwizgran
821327d62e Replace persistent logger after deleting account. 2020-07-14 11:19:40 +01:00
akwizgran
cda722a8b2 Refactor persistent logging to bramble-core. 2020-07-14 11:16:36 +01:00
akwizgran
ca5c18ece3 Show toast if log file is empty. 2020-07-13 14:49:54 +01:00
akwizgran
81ed5978d6 Add buttons for exporting persisted logs to SD card. 2020-07-13 14:49:54 +01:00
akwizgran
a63619ab47 Load the current and previous session's logs. 2020-07-13 14:49:53 +01:00
akwizgran
2d88819e80 Limit the number of lines we try to hold in memory. 2020-07-13 14:49:53 +01:00
akwizgran
fef19c1329 Flush the log stream whenever there are records to flush. 2020-07-13 14:49:53 +01:00
akwizgran
7ce91066f5 Check that createLogHandler() isn't called more than once.
This would result in multiple log files encrypted with the same key.
2020-07-13 14:49:53 +01:00
akwizgran
dfb581ef12 Remove try-with-resources to appease Animal Sniffer. 2020-07-13 14:49:53 +01:00
akwizgran
d9b4c013bb Encrypt logs on disk, store encryption key in DB. 2020-07-13 14:49:53 +01:00
akwizgran
61407c3e06 Save logs to disk. 2020-07-13 14:49:46 +01:00
969 changed files with 15923 additions and 37964 deletions

1
.gitignore vendored
View File

@@ -18,7 +18,6 @@ local.properties
# Android Studio
.idea/*
!.idea/inspectionProfiles/
!.idea/runConfigurations/
!.idea/codeStyleSettings.xml
!.idea/codeStyles

View File

@@ -1,79 +1,29 @@
image: briar/ci-image-android:latest
stages:
- test
- optional_tests
- check_reproducibility
- test
- check_reproducibility
workflow:
# when to create a CI pipeline
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never # avoids duplicate jobs for branch and MR
- if: '$CI_COMMIT_BRANCH'
- if: '$CI_COMMIT_TAG'
.base-test:
test:
stage: test
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- .gradle/wrapper
- .gradle/caches
script:
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom check compileOfficialDebugAndroidTestSources compileScreenshotDebugAndroidTestSources
after_script:
# these file change every time and should not be cached
# these file change every time but should not be cached
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
test:
extends: .base-test
stage: test
script:
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom check
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
- when: always
android test:
extends: .base-test
stage: optional_tests
image: briar/ci-image-android-emulator:latest
script:
# start emulator first, so it can fail early
- start-emulator.sh
# run normal and screenshot tests together (exclude Large tests)
- ./gradlew -Djava.security.egd=file:/dev/urandom connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.package=org.briarproject.briar.android -Pandroid.testInstrumentationRunnerArguments.notAnnotation=androidx.test.filters.LargeTest
after_script:
- adb pull /sdcard/Pictures/screenshots
artifacts:
name: "${CI_PROJECT_PATH}_${CI_JOB_STAGE}_${CI_COMMIT_REF_NAME}_${CI_COMMIT_SHA}"
paths:
- kernel.log
- logcat.txt
- briar-android/build/reports/androidTests/connected/flavors/*
- screenshots
expire_in: 3 days
when: on_failure
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: on_success
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- briar-android/**/*
when: manual
allow_failure: true
- if: '$CI_COMMIT_TAG == null'
when: manual
allow_failure: true
retry:
max: 1
tags:
- kvm
test_reproducible:
stage: check_reproducibility
@@ -81,38 +31,3 @@ test_reproducible:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
only:
- tags
.optional_tests:
stage: optional_tests
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- .gradle/wrapper
- .gradle/caches
script:
- OPTIONAL_TESTS=org.briarproject.bramble.plugin.tor.BridgeTest ./gradlew --info bramble-java:test --tests BridgeTest
after_script:
# these file change every time but should not be cached
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
bridge test:
extends: .optional_tests
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: on_success
allow_failure: true
- if: '$CI_COMMIT_TAG == null'
when: manual
allow_failure: true
pre_release_tests:
extends: .optional_tests
only:
- tags

View File

@@ -1,5 +1,8 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<AndroidXmlCodeStyleSettings>
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
<option name="IMPORT_LAYOUT_TABLE">
@@ -28,20 +31,6 @@
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value />
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<XML>

View File

@@ -1,15 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="briar">
<words>
<w>briar</w>
<w>briarproject</w>
<w>emoji</w>
<w>encrypter</w>
<w>identicon</w>
<w>introducee</w>
<w>introducees</w>
<w>introducer</w>
<w>onboarding</w>
</words>
</dictionary>
</component>

View File

@@ -1,14 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreObjectMethods" value="true" />
<option name="ignoreAnonymousClassMethods" value="false" />
</inspection_tool>
<inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
<option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" />
<option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="true" />
<option name="SUGGEST_PRIVATE_FOR_INNERS" value="true" />
</inspection_tool>
</profile>
</component>

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.briar-android" />
<module name="briar-android" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
@@ -13,7 +13,6 @@
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-android" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-java" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-api" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-headless" run_configuration_type="AndroidJUnit" />
</method>

View File

@@ -1,14 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-android" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.bramble-android" />
<module name="bramble-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-android" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,14 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-api" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.bramble-api" />
<module name="bramble-api" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-api" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,14 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-core" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.bramble-core" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-core" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,6 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.bramble-java" />
<module name="bramble-java" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
@@ -8,8 +10,11 @@
<option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,14 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-android" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.briar-android" />
<module name="briar-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,14 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-api" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.briar-api" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-api" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,14 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.briar-core" />
<module name="briar-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-headless" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.briar-headless" />
<module name="briar-headless" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="BridgeTest" type="AndroidJUnit" factoryName="Android JUnit" nameIsGenerated="true">
<module name="briar.bramble-java" />
<useClassPathOnly />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.briarproject.bramble.plugin.tor.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="org.briarproject.bramble.plugin.tor" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.plugin.tor.BridgeTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<envs>
<env name="OPTIONAL_TESTS" value="org.briarproject.bramble.plugin.tor.BridgeTest" />
</envs>
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,14 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.bramble-core" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.H2DatabasePerformanceTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,14 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar.bramble-core" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.HyperSqlDatabasePerformanceTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,51 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Instrumentation Tests (destroys DB)" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
<module name="briar.briar-android" />
<option name="TESTING_TYPE" value="1" />
<option name="METHOD_NAME" value="" />
<option name="CLASS_NAME" value="" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.android" />
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
<option name="EXTRA_OPTIONS" value="-e notAnnotation androidx.test.filters.LargeTest" />
<option name="INCLUDE_GRADLE_EXTRA_OPTIONS" value="true" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
<option name="DEBUGGER_TYPE" value="Auto" />
<Auto>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Auto>
<Hybrid>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Hybrid>
<Java />
<Native>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Native>
<Profilers>
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
<option name="STARTUP_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
</Profilers>
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="briar-headless" type="JetRunConfigurationType" singleton="true">
<module name="briar.briar-headless" />
<configuration default="false" name="briar-headless" type="JetRunConfigurationType" factoryName="Kotlin" singleton="true">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="-v" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
@@ -8,8 +8,9 @@
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.briar.headless.MainKt" />
<option name="WORKING_DIRECTORY" value="" />
<method v="2">
<option name="Make" enabled="true" />
<module name="briar-headless" />
<envs />
<method>
<option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/briar-headless" vmOptions="" scriptParameters="" />
</method>
</configuration>

View File

@@ -3,4 +3,3 @@ gen
build
.settings
src/main/res/raw/*.zip
src/main/jniLibs

View File

@@ -5,18 +5,14 @@ apply plugin: 'witness'
apply from: 'witness.gradle'
android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
packagingOptions {
doNotStrip '**/*.so'
}
compileSdkVersion 29
buildToolsVersion '29.0.2'
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 10304
versionName "1.3.4"
targetSdkVersion 28
versionCode 10209
versionName "1.2.9"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -42,8 +38,8 @@ configurations {
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.3.5.13@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.12-dev-40245c4a@zip'
tor 'org.briarproject:tor-android:0.3.5.10@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.11-2@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.24'
@@ -57,12 +53,10 @@ dependencies {
}
def torBinariesDir = 'src/main/res/raw'
def torLibsDir = 'src/main/jniLibs'
task cleanTorBinaries {
doLast {
delete fileTree(torBinariesDir) { include '*.zip' }
delete fileTree(torLibsDir) { include '**/*.so' }
}
}
@@ -73,36 +67,8 @@ task unpackTorBinaries {
copy {
from configurations.tor.collect { zipTree(it) }
into torBinariesDir
include 'geoip.zip'
}
configurations.tor.each { outer ->
zipTree(outer).each { inner ->
if (inner.name.endsWith('_arm_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'armeabi-v7a/lib$1.so'
}
} else if (inner.name.endsWith('_arm64_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'arm64-v8a/lib$1.so'
}
} else if (inner.name.endsWith('_x86_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'x86/lib$1.so'
}
} else if (inner.name.endsWith('_x86_64_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'x86_64/lib$1.so'
}
}
}
// TODO: Remove after next Tor upgrade, which won't include non-PIE binaries
include 'geoip.zip', '*_pie.zip'
}
}
dependsOn cleanTorBinaries
@@ -110,6 +76,5 @@ task unpackTorBinaries {
tasks.withType(MergeResources) {
inputs.dir torBinariesDir
inputs.dir torLibsDir
dependsOn unpackTorBinaries
}

View File

@@ -16,8 +16,6 @@
android:label="@string/app_name"
android:supportsRtl="true">
<receiver android:name=".system.AlarmReceiver" />
</application>
</manifest>

View File

@@ -6,8 +6,6 @@ import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import org.briarproject.bramble.system.AndroidTaskSchedulerModule;
import org.briarproject.bramble.system.AndroidWakefulIoExecutorModule;
import dagger.Module;
@@ -15,8 +13,6 @@ import dagger.Module;
AndroidBatteryModule.class,
AndroidNetworkModule.class,
AndroidSystemModule.class,
AndroidTaskSchedulerModule.class,
AndroidWakefulIoExecutorModule.class,
CircumventionModule.class,
ReportingModule.class,
SocksModule.class

View File

@@ -1,8 +0,0 @@
package org.briarproject.bramble;
import org.briarproject.bramble.api.system.AlarmListener;
public interface BrambleAppComponent {
AlarmListener alarmListener();
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble;
public interface BrambleApplication {
BrambleAppComponent getBrambleAppComponent();
}

View File

@@ -9,8 +9,10 @@ import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.logging.PersistentLogManager;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -20,17 +22,21 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.inject.Inject;
import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.logFileOrDir;
class AndroidAccountManager extends AccountManagerImpl
implements AccountManager {
private static final Logger LOG =
Logger.getLogger(AndroidAccountManager.class.getName());
getLogger(AndroidAccountManager.class.getName());
/**
* Directories that shouldn't be deleted when deleting the user's account.
@@ -40,13 +46,16 @@ class AndroidAccountManager extends AccountManagerImpl
protected final Context appContext;
private final SharedPreferences prefs;
private final PersistentLogManager logManager;
@Inject
AndroidAccountManager(DatabaseConfig databaseConfig,
CryptoComponent crypto, IdentityManager identityManager,
SharedPreferences prefs, Application app) {
SharedPreferences prefs, PersistentLogManager logManager,
Application app) {
super(databaseConfig, crypto, identityManager);
this.prefs = prefs;
this.logManager = logManager;
appContext = app.getApplicationContext();
}
@@ -74,6 +83,7 @@ class AndroidAccountManager extends AccountManagerImpl
LOG.info("Contents of account directory after deleting:");
logFileOrDir(LOG, INFO, getDataDir());
}
replacePersistentLogger();
}
}
@@ -134,4 +144,13 @@ class AndroidAccountManager extends AccountManagerImpl
private void addIfNotNull(Set<File> files, @Nullable File file) {
if (file != null) files.add(file);
}
private void replacePersistentLogger() {
File logDir = appContext.getDir("log", MODE_PRIVATE);
try {
logManager.addLogHandler(logDir, getLogger(""));
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
}

View File

@@ -1,11 +0,0 @@
package org.briarproject.bramble.api.system;
import android.content.Intent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AlarmListener {
void onAlarm(Intent intent);
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AndroidWakeLock {
/**
* Acquires the wake lock. This has no effect if the wake lock has already
* been acquired.
*/
void acquire();
/**
* Releases the wake lock. This has no effect if the wake lock has already
* been released.
*/
void release();
}

View File

@@ -1,38 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
@NotNullByDefault
public interface AndroidWakeLockManager {
/**
* Creates a wake lock with the given tag. The tag is only used for
* logging; the underlying OS wake lock will use its own tag.
*/
AndroidWakeLock createWakeLock(String tag);
/**
* Runs the given task while holding a wake lock.
*/
void runWakefully(Runnable r, String tag);
/**
* Submits the given task to the given executor while holding a wake lock.
* The lock is released when the task completes, or if an exception is
* thrown while submitting or running the task.
*/
void executeWakefully(Runnable r, Executor executor, String tag);
/**
* Starts a dedicated thread to run the given task asynchronously. A wake
* lock is acquired before starting the thread and released when the task
* completes, or if an exception is thrown while starting the thread or
* running the task.
* <p>
* This method should only be used for lifecycle management tasks that
* can't be run on an executor.
*/
void executeWakefully(Runnable r, String tag);
}

View File

@@ -1,34 +1,24 @@
package org.briarproject.bramble.network;
import android.annotation.TargetApi;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkInfo;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import org.briarproject.bramble.api.system.Scheduler;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -45,47 +35,36 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.list;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidNetworkManager implements NetworkManager, Service {
private static final Logger LOG =
getLogger(AndroidNetworkManager.class.getName());
Logger.getLogger(AndroidNetworkManager.class.getName());
// See android.net.wifi.WifiManager
private static final String WIFI_AP_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_AP_STATE_CHANGED";
private final TaskScheduler scheduler;
private final ScheduledExecutorService scheduler;
private final EventBus eventBus;
private final Executor eventExecutor;
private final Application app;
private final ConnectivityManager connectivityManager;
private final AtomicReference<Cancellable> connectivityCheck =
private final Context appContext;
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver networkStateReceiver = null;
@Inject
AndroidNetworkManager(TaskScheduler scheduler, EventBus eventBus,
@EventExecutor Executor eventExecutor, Application app) {
AndroidNetworkManager(@Scheduler ScheduledExecutorService scheduler,
EventBus eventBus, Application app) {
this.scheduler = scheduler;
this.eventBus = eventBus;
this.eventExecutor = eventExecutor;
this.app = app;
connectivityManager = (ConnectivityManager)
requireNonNull(app.getSystemService(CONNECTIVITY_SERVICE));
this.appContext = app.getApplicationContext();
}
@Override
@@ -100,82 +79,24 @@ class AndroidNetworkManager implements NetworkManager, Service {
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
app.registerReceiver(networkStateReceiver, filter);
appContext.registerReceiver(networkStateReceiver, filter);
}
@Override
public void stopService() {
if (networkStateReceiver != null)
app.unregisterReceiver(networkStateReceiver);
appContext.unregisterReceiver(networkStateReceiver);
}
@Override
public NetworkStatus getNetworkStatus() {
NetworkInfo net = connectivityManager.getActiveNetworkInfo();
ConnectivityManager cm = (ConnectivityManager)
appContext.getSystemService(CONNECTIVITY_SERVICE);
if (cm == null) throw new AssertionError();
NetworkInfo net = cm.getActiveNetworkInfo();
boolean connected = net != null && net.isConnected();
boolean wifi = false, ipv6Only = false;
if (connected) {
wifi = net.getType() == TYPE_WIFI;
if (SDK_INT >= 23) ipv6Only = isActiveNetworkIpv6Only();
else ipv6Only = areAllAvailableNetworksIpv6Only();
}
return new NetworkStatus(connected, wifi, ipv6Only);
}
/**
* Returns true if the
* {@link ConnectivityManager#getActiveNetwork() active network} has an
* IPv6 unicast address and no IPv4 addresses. The active network is
* assumed not to be a loopback interface.
*/
@TargetApi(23)
private boolean isActiveNetworkIpv6Only() {
Network net = connectivityManager.getActiveNetwork();
if (net == null) {
LOG.info("No active network");
return false;
}
LinkProperties props = connectivityManager.getLinkProperties(net);
if (props == null) {
LOG.info("No link properties for active network");
return false;
}
boolean hasIpv6Unicast = false;
for (LinkAddress linkAddress : props.getLinkAddresses()) {
InetAddress addr = linkAddress.getAddress();
if (addr instanceof Inet4Address) return false;
if (!addr.isMulticastAddress()) hasIpv6Unicast = true;
}
return hasIpv6Unicast;
}
/**
* Returns true if the device has at least one network interface with an
* IPv6 unicast address and no interfaces with IPv4 addresses, excluding
* loopback interfaces and interfaces that are
* {@link NetworkInterface#isUp() down}. If this method returns true and
* the device has internet access then it's via IPv6 only.
*/
private boolean areAllAvailableNetworksIpv6Only() {
try {
Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
if (interfaces == null) {
LOG.info("No network interfaces");
return false;
}
boolean hasIpv6Unicast = false;
for (NetworkInterface i : list(interfaces)) {
if (i.isLoopback() || !i.isUp()) continue;
for (InetAddress addr : list(i.getInetAddresses())) {
if (addr instanceof Inet4Address) return false;
if (!addr.isMulticastAddress()) hasIpv6Unicast = true;
}
}
return hasIpv6Unicast;
} catch (SocketException e) {
logException(LOG, WARNING, e);
return false;
}
boolean wifi = connected && net.getType() == TYPE_WIFI;
return new NetworkStatus(connected, wifi);
}
private void updateConnectionStatus() {
@@ -183,12 +104,11 @@ class AndroidNetworkManager implements NetworkManager, Service {
}
private void scheduleConnectionStatusUpdate(int delay, TimeUnit unit) {
Cancellable newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, eventExecutor,
delay, unit);
Cancellable oldConnectivityCheck =
Future<?> newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, delay, unit);
Future<?> oldConnectivityCheck =
connectivityCheck.getAndSet(newConnectivityCheck);
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel();
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);
}
private class NetworkStateReceiver extends BroadcastReceiver {

View File

@@ -1,36 +0,0 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothSocket;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import java.io.IOException;
@NotNullByDefault
class AndroidBluetoothConnectionFactory
implements BluetoothConnectionFactory<BluetoothSocket> {
private final BluetoothConnectionLimiter connectionLimiter;
private final AndroidWakeLockManager wakeLockManager;
private final TimeoutMonitor timeoutMonitor;
AndroidBluetoothConnectionFactory(
BluetoothConnectionLimiter connectionLimiter,
AndroidWakeLockManager wakeLockManager,
TimeoutMonitor timeoutMonitor) {
this.connectionLimiter = connectionLimiter;
this.wakeLockManager = wakeLockManager;
this.timeoutMonitor = timeoutMonitor;
}
@Override
public DuplexTransportConnection wrapSocket(DuplexPlugin plugin,
BluetoothSocket s) throws IOException {
return new AndroidBluetoothTransportConnection(plugin,
connectionLimiter, wakeLockManager, timeoutMonitor, s);
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
@@ -10,6 +9,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
@@ -31,6 +31,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.Nullable;
@@ -59,41 +60,35 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidBluetoothPlugin extends
AbstractBluetoothPlugin<BluetoothSocket, BluetoothServerSocket> {
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG =
getLogger(AndroidBluetoothPlugin.class.getName());
private static final int MAX_DISCOVERY_MS = 10_000;
private final ScheduledExecutorService scheduler;
private final AndroidExecutor androidExecutor;
private final Application app;
private final Context appContext;
private final Clock clock;
private volatile boolean wasEnabledByUs = false;
private volatile BluetoothStateReceiver receiver = null;
// Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null;
private volatile boolean stopDiscoverAndConnect;
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
BluetoothConnectionFactory<BluetoothSocket> connectionFactory,
Executor ioExecutor,
Executor wakefulIoExecutor,
SecureRandom secureRandom,
AndroidExecutor androidExecutor,
Application app,
Clock clock,
Backoff backoff,
PluginCallback callback,
int maxLatency,
TimeoutMonitor timeoutMonitor, Executor ioExecutor,
SecureRandom secureRandom, ScheduledExecutorService scheduler,
AndroidExecutor androidExecutor, Context appContext, Clock clock,
Backoff backoff, PluginCallback callback, int maxLatency,
int maxIdleTime) {
super(connectionLimiter, connectionFactory, ioExecutor,
wakefulIoExecutor, secureRandom, backoff, callback,
maxLatency, maxIdleTime);
super(connectionLimiter, timeoutMonitor, ioExecutor, secureRandom,
backoff, callback, maxLatency, maxIdleTime);
this.scheduler = scheduler;
this.androidExecutor = androidExecutor;
this.app = app;
this.appContext = appContext;
this.clock = clock;
}
@@ -105,13 +100,13 @@ class AndroidBluetoothPlugin extends
filter.addAction(ACTION_STATE_CHANGED);
filter.addAction(ACTION_SCAN_MODE_CHANGED);
receiver = new BluetoothStateReceiver();
app.registerReceiver(receiver, filter);
appContext.registerReceiver(receiver, filter);
}
@Override
public void stop() {
super.stop();
if (receiver != null) app.unregisterReceiver(receiver);
if (receiver != null) appContext.unregisterReceiver(receiver);
}
@Override
@@ -133,11 +128,42 @@ class AndroidBluetoothPlugin extends
return adapter != null && adapter.isEnabled();
}
@Override
void enableAdapter() {
if (adapter != null && !adapter.isEnabled()) {
if (adapter.enable()) {
LOG.info("Enabling Bluetooth");
wasEnabledByUs = true;
} else {
LOG.info("Could not enable Bluetooth");
}
}
}
@Override
void disableAdapterIfEnabledByUs() {
if (isAdapterEnabled() && wasEnabledByUs) {
if (adapter.disable()) LOG.info("Disabling Bluetooth");
else LOG.info("Could not disable Bluetooth");
wasEnabledByUs = false;
}
}
@Override
void setEnabledByUs() {
wasEnabledByUs = true;
}
@Override
void onAdapterDisabled() {
super.onAdapterDisabled();
wasEnabledByUs = false;
}
@Override
@Nullable
String getBluetoothAddress() {
if (adapter == null) return null;
String address = AndroidUtils.getBluetoothAddress(app, adapter);
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
return address.isEmpty() ? null : address;
}
@@ -155,7 +181,13 @@ class AndroidBluetoothPlugin extends
@Override
DuplexTransportConnection acceptConnection(BluetoothServerSocket ss)
throws IOException {
return connectionFactory.wrapSocket(this, ss.accept());
return wrapSocket(ss.accept());
}
private DuplexTransportConnection wrapSocket(BluetoothSocket s)
throws IOException {
return new AndroidBluetoothTransportConnection(this, connectionLimiter,
timeoutMonitor, appContext, scheduler, s);
}
@Override
@@ -172,15 +204,10 @@ class AndroidBluetoothPlugin extends
try {
s = d.createInsecureRfcommSocketToServiceRecord(u);
s.connect();
return connectionFactory.wrapSocket(this, s);
return wrapSocket(s);
} catch (IOException e) {
IoUtils.tryToClose(s, LOG, WARNING);
throw e;
} catch (NullPointerException e) {
// BluetoothSocket#connect() may throw an NPE under unknown
// circumstances
IoUtils.tryToClose(s, LOG, WARNING);
throw new IOException(e);
}
}
@@ -188,40 +215,22 @@ class AndroidBluetoothPlugin extends
@Nullable
DuplexTransportConnection discoverAndConnect(String uuid) {
if (adapter == null) return null;
if (!discoverSemaphore.tryAcquire()) {
LOG.info("Discover already running");
return null;
}
try {
stopDiscoverAndConnect = false;
for (String address : discoverDevices()) {
if (stopDiscoverAndConnect) {
break;
}
try {
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address));
return connectTo(address, uuid);
} catch (IOException e) {
if (LOG.isLoggable(INFO)) {
LOG.info("Could not connect to "
+ scrubMacAddress(address));
}
for (String address : discoverDevices()) {
try {
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address));
return connectTo(address, uuid);
} catch (IOException e) {
if (LOG.isLoggable(INFO)) {
LOG.info("Could not connect to "
+ scrubMacAddress(address));
}
}
} finally {
discoverSemaphore.release();
}
LOG.info("Could not connect to any devices");
return null;
}
@Override
public void stopDiscoverAndConnect() {
stopDiscoverAndConnect = true;
adapter.cancelDiscovery();
}
private Collection<String> discoverDevices() {
List<String> addresses = new ArrayList<>();
BlockingQueue<Intent> intents = new LinkedBlockingQueue<>();
@@ -230,7 +239,7 @@ class AndroidBluetoothPlugin extends
filter.addAction(ACTION_DISCOVERY_STARTED);
filter.addAction(ACTION_DISCOVERY_FINISHED);
filter.addAction(ACTION_FOUND);
app.registerReceiver(receiver, filter);
appContext.registerReceiver(receiver, filter);
try {
if (adapter.startDiscovery()) {
long now = clock.currentTimeMillis();
@@ -267,7 +276,7 @@ class AndroidBluetoothPlugin extends
} finally {
LOG.info("Cancelling discovery");
adapter.cancelDiscovery();
app.unregisterReceiver(receiver);
appContext.unregisterReceiver(receiver);
}
// Shuffle the addresses so we don't always try the same one first
shuffle(addresses);

View File

@@ -1,11 +1,9 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.app.Application;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -14,15 +12,13 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.security.SecureRandom;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
@@ -36,32 +32,25 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final AndroidExecutor androidExecutor;
private final AndroidWakeLockManager wakeLockManager;
private final Application app;
private final Context appContext;
private final SecureRandom secureRandom;
private final EventBus eventBus;
private final Clock clock;
private final TimeoutMonitor timeoutMonitor;
private final BackoffFactory backoffFactory;
@Inject
public AndroidBluetoothPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
AndroidExecutor androidExecutor,
AndroidWakeLockManager wakeLockManager,
Application app,
SecureRandom secureRandom,
EventBus eventBus,
Clock clock,
TimeoutMonitor timeoutMonitor,
BackoffFactory backoffFactory) {
public AndroidBluetoothPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler,
AndroidExecutor androidExecutor, Context appContext,
SecureRandom secureRandom, EventBus eventBus, Clock clock,
TimeoutMonitor timeoutMonitor, BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.scheduler = scheduler;
this.androidExecutor = androidExecutor;
this.wakeLockManager = wakeLockManager;
this.app = app;
this.appContext = appContext;
this.secureRandom = secureRandom;
this.eventBus = eventBus;
this.clock = clock;
@@ -83,15 +72,12 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(PluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl(eventBus);
BluetoothConnectionFactory<BluetoothSocket> connectionFactory =
new AndroidBluetoothConnectionFactory(connectionLimiter,
wakeLockManager, timeoutMonitor);
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
connectionLimiter, connectionFactory, ioExecutor,
wakefulIoExecutor, secureRandom, androidExecutor, app,
clock, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME);
connectionLimiter, timeoutMonitor, ioExecutor, secureRandom,
scheduler, androidExecutor, appContext, clock, backoff,
callback, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,19 +1,26 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.PowerManager;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.util.RenewableWakeLock;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ScheduledExecutorService;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS;
import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag;
import static org.briarproject.bramble.util.AndroidUtils.isValidBluetoothAddress;
@NotNullByDefault
@@ -21,21 +28,25 @@ class AndroidBluetoothTransportConnection
extends AbstractDuplexTransportConnection {
private final BluetoothConnectionLimiter connectionLimiter;
private final RenewableWakeLock wakeLock;
private final BluetoothSocket socket;
private final InputStream in;
private final AndroidWakeLock wakeLock;
AndroidBluetoothTransportConnection(Plugin plugin,
BluetoothConnectionLimiter connectionLimiter,
AndroidWakeLockManager wakeLockManager,
TimeoutMonitor timeoutMonitor,
BluetoothSocket socket) throws IOException {
TimeoutMonitor timeoutMonitor, Context appContext,
ScheduledExecutorService scheduler, BluetoothSocket socket)
throws IOException {
super(plugin);
this.connectionLimiter = connectionLimiter;
this.socket = socket;
in = timeoutMonitor.createTimeoutInputStream(
socket.getInputStream(), plugin.getMaxIdleTime() * 2);
wakeLock = wakeLockManager.createWakeLock("BluetoothConnection");
PowerManager powerManager = (PowerManager)
requireNonNull(appContext.getSystemService(POWER_SERVICE));
String tag = getWakeLockTag(appContext);
wakeLock = new RenewableWakeLock(powerManager, scheduler,
PARTIAL_WAKE_LOCK, tag, 1, MINUTES);
wakeLock.acquire();
String address = socket.getRemoteDevice().getAddress();
if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address);
@@ -55,7 +66,6 @@ class AndroidBluetoothTransportConnection
protected void closeConnection(boolean exception) throws IOException {
try {
socket.close();
in.close();
} finally {
wakeLock.release();
connectionLimiter.connectionClosed(this);

View File

@@ -1,7 +1,7 @@
package org.briarproject.bramble.plugin.tcp;
import android.annotation.TargetApi;
import android.app.Application;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -42,7 +42,6 @@ import static java.util.Collections.list;
import static java.util.Collections.singletonList;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.DEFAULT_PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
@@ -62,22 +61,20 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
private volatile SocketFactory socketFactory;
AndroidLanTcpPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Application app,
Backoff backoff,
PluginCallback callback,
int maxLatency,
int maxIdleTime,
int connectionTimeout) {
super(ioExecutor, wakefulIoExecutor, backoff, callback, maxLatency,
maxIdleTime, connectionTimeout);
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
Backoff backoff, PluginCallback callback, int maxLatency,
int maxIdleTime, int connectionTimeout) {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime,
connectionTimeout);
// Don't execute more than one connection status check at a time
connectionStatusExecutor =
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
connectivityManager = (ConnectivityManager)
requireNonNull(app.getSystemService(CONNECTIVITY_SERVICE));
wifiManager = (WifiManager) app.getSystemService(WIFI_SERVICE);
ConnectivityManager connectivityManager = (ConnectivityManager)
appContext.getSystemService(CONNECTIVITY_SERVICE);
if (connectivityManager == null) throw new AssertionError();
this.connectivityManager = connectivityManager;
wifiManager = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
socketFactory = SocketFactory.getDefault();
}
@@ -277,11 +274,11 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
// make outgoing connections on API 21+ if another network
// has internet access
socketFactory = SocketFactory.getDefault();
bind();
if (s == INACTIVE) bind();
} else {
LOG.info("Connected to wifi");
socketFactory = getSocketFactory();
bind();
if (s == INACTIVE) bind();
}
});
}

View File

@@ -1,9 +1,8 @@
package org.briarproject.bramble.plugin.tcp;
import android.app.Application;
import android.content.Context;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -11,12 +10,10 @@ import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
@@ -31,22 +28,17 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final int MAX_POLLING_INTERVAL = 600_000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final EventBus eventBus;
private final BackoffFactory backoffFactory;
private final Application app;
private final Context appContext;
@Inject
public AndroidLanTcpPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
EventBus eventBus,
BackoffFactory backoffFactory,
Application app) {
public AndroidLanTcpPluginFactory(Executor ioExecutor, EventBus eventBus,
BackoffFactory backoffFactory, Context appContext) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory;
this.app = app;
this.appContext = appContext;
}
@Override
@@ -64,8 +56,8 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
wakefulIoExecutor, app, backoff, callback,
MAX_LATENCY, MAX_IDLE_TIME, CONNECTION_TIMEOUT);
appContext, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME,
CONNECTION_TIMEOUT);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,9 +1,10 @@
package org.briarproject.bramble.plugin.tor;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
@@ -11,76 +12,49 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.RenewableWakeLock;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.concurrent.ScheduledExecutorService;
import javax.net.SocketFactory;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidTorPlugin extends TorPlugin {
private static final List<String> LIBRARY_ARCHITECTURES =
asList("armeabi-v7a", "arm64-v8a", "x86", "x86_64");
private final Context appContext;
private final RenewableWakeLock wakeLock;
private static final String TOR_LIB_NAME = "libtor.so";
private static final String OBFS4_LIB_NAME = "libobfs4proxy.so";
private static final Logger LOG =
getLogger(AndroidTorPlugin.class.getName());
private final Application app;
private final AndroidWakeLock wakeLock;
private final File torLib, obfs4Lib;
AndroidTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Application app,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
AndroidTorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
AndroidWakeLockManager wakeLockManager,
Backoff backoff,
BatteryManager batteryManager, Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
int maxLatency,
int maxIdleTime,
File torDirectory) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture, maxLatency,
maxIdleTime, torDirectory);
this.app = app;
wakeLock = wakeLockManager.createWakeLock("TorPlugin");
String nativeLibDir = app.getApplicationInfo().nativeLibraryDir;
torLib = new File(nativeLibDir, TOR_LIB_NAME);
obfs4Lib = new File(nativeLibDir, OBFS4_LIB_NAME);
PluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext;
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
if (pm == null) throw new AssertionError();
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
getWakeLockTag(appContext), 1, MINUTES);
}
@Override
@@ -91,8 +65,8 @@ class AndroidTorPlugin extends TorPlugin {
@Override
protected long getLastUpdateTime() {
try {
PackageManager pm = app.getPackageManager();
PackageInfo pi = pm.getPackageInfo(app.getPackageName(), 0);
PackageManager pm = appContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0);
return pi.lastUpdateTime;
} catch (NameNotFoundException e) {
throw new AssertionError(e);
@@ -111,112 +85,4 @@ class AndroidTorPlugin extends TorPlugin {
super.stop();
wakeLock.release();
}
@Override
protected File getTorExecutableFile() {
return torLib.exists() ? torLib : super.getTorExecutableFile();
}
@Override
protected File getObfs4ExecutableFile() {
return obfs4Lib.exists() ? obfs4Lib : super.getObfs4ExecutableFile();
}
@Override
protected void installTorExecutable() throws IOException {
File extracted = super.getTorExecutableFile();
if (torLib.exists()) {
// If an older version left behind a Tor binary, delete it
if (extracted.exists()) {
if (extracted.delete()) LOG.info("Deleted Tor binary");
else LOG.info("Failed to delete Tor binary");
}
} else if (SDK_INT < 29) {
// The binary wasn't extracted at install time. Try to extract it
extractLibraryFromApk(TOR_LIB_NAME, extracted);
} else {
// No point extracting the binary, we won't be allowed to execute it
throw new FileNotFoundException(torLib.getAbsolutePath());
}
}
@Override
protected void installObfs4Executable() throws IOException {
File extracted = super.getObfs4ExecutableFile();
if (obfs4Lib.exists()) {
// If an older version left behind an obfs4 binary, delete it
if (extracted.exists()) {
if (extracted.delete()) LOG.info("Deleted obfs4 binary");
else LOG.info("Failed to delete obfs4 binary");
}
} else if (SDK_INT < 29) {
// The binary wasn't extracted at install time. Try to extract it
extractLibraryFromApk(OBFS4_LIB_NAME, extracted);
} else {
// No point extracting the binary, we won't be allowed to execute it
throw new FileNotFoundException(obfs4Lib.getAbsolutePath());
}
}
private void extractLibraryFromApk(String libName, File dest)
throws IOException {
File sourceDir = new File(app.getApplicationInfo().sourceDir);
if (sourceDir.isFile()) {
// Look for other APK files in the same directory, if we're allowed
File parent = sourceDir.getParentFile();
if (parent != null) sourceDir = parent;
}
List<String> libPaths = getSupportedLibraryPaths(libName);
for (File apk : findApkFiles(sourceDir)) {
ZipInputStream zin = new ZipInputStream(new FileInputStream(apk));
for (ZipEntry e = zin.getNextEntry(); e != null;
e = zin.getNextEntry()) {
if (libPaths.contains(e.getName())) {
if (LOG.isLoggable(INFO)) {
LOG.info("Extracting " + e.getName()
+ " from " + apk.getAbsolutePath());
}
extract(zin, dest); // Zip input stream will be closed
return;
}
}
zin.close();
}
throw new FileNotFoundException(libName);
}
/**
* Returns all files with the extension .apk or .APK under the given root.
*/
private List<File> findApkFiles(File root) {
List<File> files = new ArrayList<>();
findApkFiles(root, files);
return files;
}
private void findApkFiles(File f, List<File> files) {
if (f.isFile() && f.getName().toLowerCase().endsWith(".apk")) {
files.add(f);
} else if (f.isDirectory()) {
File[] children = f.listFiles();
if (children != null) {
for (File child : children) findApkFiles(child, files);
}
}
}
/**
* Returns the paths at which libraries with the given name would be found
* inside an APK file, for all architectures supported by the device, in
* order of preference.
*/
private List<String> getSupportedLibraryPaths(String libName) {
List<String> architectures = new ArrayList<>();
for (String abi : AndroidUtils.getSupportedArchitectures()) {
if (LIBRARY_ARCHITECTURES.contains(abi)) {
architectures.add("lib/" + abi + "/" + libName);
}
}
return architectures;
}
}

View File

@@ -1,33 +1,28 @@
package org.briarproject.bramble.plugin.tor;
import android.app.Application;
import android.content.Context;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.bramble.util.AndroidUtils;
import java.io.File;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.net.SocketFactory;
@Immutable
@@ -43,8 +38,9 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor, wakefulIoExecutor;
private final Application app;
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final EventBus eventBus;
@@ -53,28 +49,18 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final AndroidWakeLockManager wakeLockManager;
private final Clock clock;
private final File torDirectory;
@Inject
public AndroidTorPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
Application app,
NetworkManager networkManager,
LocationUtils locationUtils,
EventBus eventBus,
SocketFactory torSocketFactory,
BackoffFactory backoffFactory,
ResourceProvider resourceProvider,
public AndroidTorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
AndroidWakeLockManager wakeLockManager,
Clock clock,
@TorDirectory File torDirectory) {
BatteryManager batteryManager, Clock clock) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.app = app;
this.scheduler = scheduler;
this.appContext = appContext;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.eventBus = eventBus;
@@ -83,9 +69,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.wakeLockManager = wakeLockManager;
this.clock = clock;
this.torDirectory = torDirectory;
}
@Override
@@ -128,12 +112,11 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor,
wakefulIoExecutor, app, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, wakeLockManager,
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory);
MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,18 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
interface AlarmConstants {
/**
* Request code for the broadcast intent attached to the periodic alarm.
*/
int REQUEST_ALARM = 1;
/**
* Key for storing the process ID in the extras of the periodic alarm's
* intent. This allows us to ignore alarms scheduled by dead processes.
*/
String EXTRA_PID = "org.briarproject.bramble.EXTRA_PID";
}

View File

@@ -1,17 +0,0 @@
package org.briarproject.bramble.system;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.briarproject.bramble.BrambleApplication;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
BrambleApplication app =
(BrambleApplication) ctx.getApplicationContext();
app.getBrambleAppComponent().alarmListener().onAlarm(intent);
}
}

View File

@@ -6,6 +6,8 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ContentResolver;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Parcel;
import android.os.StrictMode;
@@ -15,10 +17,12 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static android.content.Context.WIFI_SERVICE;
import static android.os.Build.VERSION.SDK_INT;
import static android.provider.Settings.Secure.ANDROID_ID;
@@ -48,6 +52,15 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
if (id != null) out.writeUTF(id);
Parcel parcel = Parcel.obtain();
WifiManager wm = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
if (wm != null) {
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
if (configs != null) {
for (WifiConfiguration config : configs)
parcel.writeParcelable(config, 0);
}
}
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) {
for (BluetoothDevice device : bt.getBondedDevices())

View File

@@ -1,17 +1,12 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import javax.inject.Singleton;
@@ -21,23 +16,6 @@ import dagger.Provides;
@Module
public class AndroidSystemModule {
private final ScheduledExecutorService scheduledExecutorService;
public AndroidSystemModule() {
// Discard tasks that are submitted during shutdown
RejectedExecutionHandler policy =
new ScheduledThreadPoolExecutor.DiscardPolicy();
scheduledExecutorService = new ScheduledThreadPoolExecutor(1, policy);
}
@Provides
@Singleton
ScheduledExecutorService provideScheduledExecutorService(
LifecycleManager lifecycleManager) {
lifecycleManager.registerForShutdown(scheduledExecutorService);
return scheduledExecutorService;
}
@Provides
@Singleton
SecureRandomProvider provideSecureRandomProvider(
@@ -69,11 +47,4 @@ public class AndroidSystemModule {
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
return provider;
}
@Provides
@Singleton
AndroidWakeLockManager provideWakeLockManager(
AndroidWakeLockManagerImpl wakeLockManager) {
return wakeLockManager;
}
}

View File

@@ -1,242 +0,0 @@
package org.briarproject.bramble.system;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Process;
import android.os.SystemClock;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.Wakeful;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.INTERVAL_FIFTEEN_MINUTES;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
import static android.content.Context.ALARM_SERVICE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.system.AlarmConstants.EXTRA_PID;
import static org.briarproject.bramble.system.AlarmConstants.REQUEST_ALARM;
@ThreadSafe
@NotNullByDefault
class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
private static final Logger LOG =
getLogger(AndroidTaskScheduler.class.getName());
private static final long ALARM_MS = INTERVAL_FIFTEEN_MINUTES;
private final Application app;
private final AndroidWakeLockManager wakeLockManager;
private final ScheduledExecutorService scheduledExecutorService;
private final AlarmManager alarmManager;
private final Object lock = new Object();
@GuardedBy("lock")
private final Queue<ScheduledTask> tasks = new PriorityQueue<>();
AndroidTaskScheduler(Application app,
AndroidWakeLockManager wakeLockManager,
ScheduledExecutorService scheduledExecutorService) {
this.app = app;
this.wakeLockManager = wakeLockManager;
this.scheduledExecutorService = scheduledExecutorService;
alarmManager = (AlarmManager)
requireNonNull(app.getSystemService(ALARM_SERVICE));
}
@Override
public void startService() {
scheduleAlarm();
}
@Override
public void stopService() {
cancelAlarm();
}
@Override
public Cancellable schedule(Runnable task, Executor executor, long delay,
TimeUnit unit) {
AtomicBoolean cancelled = new AtomicBoolean(false);
return schedule(task, executor, delay, unit, cancelled);
}
@Override
public Cancellable scheduleWithFixedDelay(Runnable task, Executor executor,
long delay, long interval, TimeUnit unit) {
AtomicBoolean cancelled = new AtomicBoolean(false);
return scheduleWithFixedDelay(task, executor, delay, interval, unit,
cancelled);
}
@Override
public void onAlarm(Intent intent) {
wakeLockManager.runWakefully(() -> {
int extraPid = intent.getIntExtra(EXTRA_PID, -1);
int currentPid = Process.myPid();
if (extraPid == currentPid) {
LOG.info("Alarm");
rescheduleAlarm();
runDueTasks();
} else if (LOG.isLoggable(INFO)) {
LOG.info("Ignoring alarm with PID " + extraPid
+ ", current PID is " + currentPid);
}
}, "TaskAlarm");
}
private Cancellable schedule(Runnable task, Executor executor, long delay,
TimeUnit unit, AtomicBoolean cancelled) {
long now = SystemClock.elapsedRealtime();
long dueMillis = now + MILLISECONDS.convert(delay, unit);
Runnable wakeful = () ->
wakeLockManager.executeWakefully(task, executor, "TaskHandoff");
Future<?> check = scheduleCheckForDueTasks(delay, unit);
ScheduledTask s = new ScheduledTask(wakeful, dueMillis, check,
cancelled);
synchronized (lock) {
tasks.add(s);
}
return s;
}
private Cancellable scheduleWithFixedDelay(Runnable task, Executor executor,
long delay, long interval, TimeUnit unit, AtomicBoolean cancelled) {
// All executions of this periodic task share a cancelled flag
Runnable wrapped = () -> {
task.run();
scheduleWithFixedDelay(task, executor, interval, interval, unit,
cancelled);
};
return schedule(wrapped, executor, delay, unit, cancelled);
}
private Future<?> scheduleCheckForDueTasks(long delay, TimeUnit unit) {
Runnable wakeful = () -> wakeLockManager.runWakefully(
this::runDueTasks, "TaskScheduler");
return scheduledExecutorService.schedule(wakeful, delay, unit);
}
@Wakeful
private void runDueTasks() {
long now = SystemClock.elapsedRealtime();
List<ScheduledTask> due = new ArrayList<>();
synchronized (lock) {
while (true) {
ScheduledTask s = tasks.peek();
if (s == null || s.dueMillis > now) break;
due.add(tasks.remove());
}
}
if (LOG.isLoggable(INFO)) {
LOG.info("Running " + due.size() + " due tasks");
}
for (ScheduledTask s : due) {
if (LOG.isLoggable(INFO)) {
LOG.info("Task is " + (now - s.dueMillis) + " ms overdue");
}
s.run();
}
}
private void scheduleAlarm() {
if (SDK_INT >= 23) scheduleIdleAlarm();
else scheduleInexactRepeatingAlarm();
}
private void rescheduleAlarm() {
// If SDK_INT < 23 the alarm repeats automatically
if (SDK_INT >= 23) scheduleIdleAlarm();
}
private void cancelAlarm() {
alarmManager.cancel(getAlarmPendingIntent());
}
private void scheduleInexactRepeatingAlarm() {
alarmManager.setInexactRepeating(ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + ALARM_MS, ALARM_MS,
getAlarmPendingIntent());
}
@TargetApi(23)
private void scheduleIdleAlarm() {
alarmManager.setAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + ALARM_MS,
getAlarmPendingIntent());
}
private PendingIntent getAlarmPendingIntent() {
Intent i = new Intent(app, AlarmReceiver.class);
i.putExtra(EXTRA_PID, android.os.Process.myPid());
return PendingIntent.getBroadcast(app, REQUEST_ALARM, i,
FLAG_CANCEL_CURRENT);
}
private class ScheduledTask
implements Runnable, Cancellable, Comparable<ScheduledTask> {
private final Runnable task;
private final long dueMillis;
private final Future<?> check;
private final AtomicBoolean cancelled;
public ScheduledTask(Runnable task, long dueMillis,
Future<?> check, AtomicBoolean cancelled) {
this.task = task;
this.dueMillis = dueMillis;
this.check = check;
this.cancelled = cancelled;
}
@Override
public void run() {
if (!cancelled.get()) task.run();
}
@Override
public void cancel() {
// Cancel any future executions of this task
cancelled.set(true);
// Cancel the scheduled check for due tasks
check.cancel(false);
// Remove the task from the queue
synchronized (lock) {
tasks.remove(this);
}
}
@Override
public int compareTo(ScheduledTask s) {
//noinspection UseCompareMethod
if (dueMillis < s.dueMillis) return -1;
if (dueMillis > s.dueMillis) return 1;
return 0;
}
}
}

View File

@@ -1,49 +0,0 @@
package org.briarproject.bramble.system;
import android.app.Application;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidTaskSchedulerModule {
public static class EagerSingletons {
@Inject
AndroidTaskScheduler scheduler;
}
@Provides
@Singleton
AndroidTaskScheduler provideAndroidTaskScheduler(
LifecycleManager lifecycleManager, Application app,
AndroidWakeLockManager wakeLockManager,
ScheduledExecutorService scheduledExecutorService) {
AndroidTaskScheduler scheduler = new AndroidTaskScheduler(app,
wakeLockManager, scheduledExecutorService);
lifecycleManager.registerService(scheduler);
return scheduler;
}
@Provides
@Singleton
AlarmListener provideAlarmListener(AndroidTaskScheduler scheduler) {
return scheduler;
}
@Provides
@Singleton
TaskScheduler provideTaskScheduler(AndroidTaskScheduler scheduler) {
return scheduler;
}
}

View File

@@ -1,74 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Level.FINE;
import static java.util.logging.Logger.getLogger;
/**
* A wrapper around a {@link SharedWakeLock} that provides the more convenient
* semantics of {@link AndroidWakeLock} (i.e. calls to acquire() and release()
* don't need to be balanced).
*/
@ThreadSafe
@NotNullByDefault
class AndroidWakeLockImpl implements AndroidWakeLock {
private static final Logger LOG =
getLogger(AndroidWakeLockImpl.class.getName());
private static final AtomicInteger INSTANCE_ID = new AtomicInteger(0);
private final SharedWakeLock sharedWakeLock;
private final String tag;
private final Object lock = new Object();
@GuardedBy("lock")
private boolean held = false;
AndroidWakeLockImpl(SharedWakeLock sharedWakeLock, String tag) {
this.sharedWakeLock = sharedWakeLock;
this.tag = tag + "_" + INSTANCE_ID.getAndIncrement();
}
@Override
public void acquire() {
synchronized (lock) {
if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already acquired");
}
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " acquiring shared wake lock");
}
held = true;
sharedWakeLock.acquire();
}
}
}
@Override
public void release() {
synchronized (lock) {
if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " releasing shared wake lock");
}
held = false;
sharedWakeLock.release();
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already released");
}
}
}
}
}

View File

@@ -1,125 +0,0 @@
package org.briarproject.bramble.system;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.PowerManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@NotNullByDefault
class AndroidWakeLockManagerImpl implements AndroidWakeLockManager {
/**
* How often to replace the wake lock.
*/
private static final long LOCK_DURATION_MS = MINUTES.toMillis(1);
/**
* Automatically release the lock this many milliseconds after it's due
* to have been replaced and released.
*/
private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(30);
private final SharedWakeLock sharedWakeLock;
@Inject
AndroidWakeLockManagerImpl(Application app,
ScheduledExecutorService scheduledExecutorService) {
PowerManager powerManager = (PowerManager)
requireNonNull(app.getSystemService(POWER_SERVICE));
String tag = getWakeLockTag(app);
sharedWakeLock = new RenewableWakeLock(powerManager,
scheduledExecutorService, PARTIAL_WAKE_LOCK, tag,
LOCK_DURATION_MS, SAFETY_MARGIN_MS);
}
@Override
public AndroidWakeLock createWakeLock(String tag) {
return new AndroidWakeLockImpl(sharedWakeLock, tag);
}
@Override
public void runWakefully(Runnable r, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
r.run();
} finally {
wakeLock.release();
}
}
@Override
public void executeWakefully(Runnable r, Executor executor, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
executor.execute(() -> {
try {
r.run();
} finally {
// Release the wake lock if the task throws an exception
wakeLock.release();
}
});
} catch (Exception e) {
// Release the wake lock if the executor throws an exception when
// we submit the task (in which case the release() call above won't
// happen)
wakeLock.release();
throw e;
}
}
@Override
public void executeWakefully(Runnable r, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
new Thread(() -> {
try {
r.run();
} finally {
wakeLock.release();
}
}).start();
} catch (Exception e) {
wakeLock.release();
throw e;
}
}
private String getWakeLockTag(Context ctx) {
PackageManager pm = ctx.getPackageManager();
if (isInstalled(pm, "com.huawei.powergenie")) {
return "LocationManagerService";
} else if (isInstalled(pm, "com.evenwell.PowerMonitor")) {
return "AudioIn";
}
return ctx.getPackageName();
}
private boolean isInstalled(PackageManager pm, String packageName) {
try {
pm.getPackageInfo(packageName, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}

View File

@@ -1,23 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;
import dagger.Module;
import dagger.Provides;
@Module
public
class AndroidWakefulIoExecutorModule {
@Provides
@WakefulIoExecutor
Executor provideWakefulIoExecutor(@IoExecutor Executor ioExecutor,
AndroidWakeLockManager wakeLockManager) {
return r -> wakeLockManager.executeWakefully(r, ioExecutor,
"WakefulIoExecutor");
}
}

View File

@@ -1,130 +0,0 @@
package org.briarproject.bramble.system;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@ThreadSafe
@NotNullByDefault
class RenewableWakeLock implements SharedWakeLock {
private static final Logger LOG =
getLogger(RenewableWakeLock.class.getName());
private final PowerManager powerManager;
private final ScheduledExecutorService scheduledExecutorService;
private final int levelAndFlags;
private final String tag;
private final long durationMs, safetyMarginMs;
private final Object lock = new Object();
@GuardedBy("lock")
@Nullable
private WakeLock wakeLock;
@GuardedBy("lock")
@Nullable
private Future<?> future;
@GuardedBy("lock")
private int refCount = 0;
@GuardedBy("lock")
private long acquired = 0;
RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduledExecutorService,
int levelAndFlags,
String tag,
long durationMs,
long safetyMarginMs) {
this.powerManager = powerManager;
this.scheduledExecutorService = scheduledExecutorService;
this.levelAndFlags = levelAndFlags;
this.tag = tag;
this.durationMs = durationMs;
this.safetyMarginMs = safetyMarginMs;
}
@Override
public void acquire() {
synchronized (lock) {
refCount++;
if (refCount == 1) {
if (LOG.isLoggable(INFO)) {
LOG.info("Acquiring wake lock " + tag);
}
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
// We do our own reference counting so we can replace the lock
// TODO: Check whether using a ref-counted wake lock affects
// power management apps
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs);
future = scheduledExecutorService.schedule(this::renew,
durationMs, MILLISECONDS);
acquired = android.os.SystemClock.elapsedRealtime();
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
}
}
private void renew() {
if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
long now = android.os.SystemClock.elapsedRealtime();
long expiry = acquired + durationMs + safetyMarginMs;
if (now > expiry && LOG.isLoggable(WARNING)) {
LOG.warning("Wake lock expired " + (now - expiry) + " ms ago");
}
WakeLock oldWakeLock = wakeLock;
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs);
oldWakeLock.release();
future = scheduledExecutorService.schedule(this::renew, durationMs,
MILLISECONDS);
acquired = now;
}
}
@Override
public void release() {
synchronized (lock) {
refCount--;
if (refCount == 0) {
if (LOG.isLoggable(INFO)) {
LOG.info("Releasing wake lock " + tag);
}
requireNonNull(future).cancel(false);
future = null;
requireNonNull(wakeLock).release();
wakeLock = null;
acquired = 0;
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
}
}
}

View File

@@ -1,22 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock;
@NotNullByDefault
interface SharedWakeLock {
/**
* Acquires the wake lock. This increments the wake lock's reference count,
* so unlike {@link AndroidWakeLock#acquire()} every call to this method
* must be followed by a balancing call to {@link #release()}.
*/
void acquire();
/**
* Releases the wake lock. This decrements the wake lock's reference count,
* so unlike {@link AndroidWakeLock#release()} every call to this method
* must follow a balancing call to {@link #acquire()}.
*/
void release();
}

View File

@@ -3,6 +3,8 @@ package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
@@ -10,20 +12,17 @@ import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Scanner;
import javax.annotation.Nullable;
import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT;
import static java.lang.Runtime.getRuntime;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@@ -34,7 +33,6 @@ public class AndroidUtils {
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
private static final String STORED_REPORTS = "dev-reports";
private static final String STORED_LOGCAT = "dev-logcat";
public static Collection<String> getSupportedArchitectures() {
List<String> abis = new ArrayList<>();
@@ -111,27 +109,27 @@ public class AndroidUtils {
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
}
public static File getLogcatFile(Context ctx) {
return new File(ctx.getFilesDir(), STORED_LOGCAT);
}
/**
* Returns an array of supported content types for image attachments.
* GIFs can't be compressed on API < 24 so they're not supported.
* <p>
* TODO: Remove this restriction when large message support is added
*/
public static String[] getSupportedImageContentTypes() {
return new String[] {"image/jpeg", "image/png", "image/gif"};
if (SDK_INT < 24) return new String[] {"image/jpeg", "image/png"};
else return new String[] {"image/jpeg", "image/png", "image/gif"};
}
@Nullable
public static String getSystemProperty(String propName) {
try {
Process p = getRuntime().exec("getprop " + propName);
Scanner s = new Scanner(p.getInputStream());
String line = s.nextLine();
s.close();
return line;
} catch (SecurityException | IOException e) {
return null;
public static String getWakeLockTag(Context ctx) {
PackageManager pm = ctx.getPackageManager();
for (PackageInfo info : pm.getInstalledPackages(0)) {
String name = info.packageName.toLowerCase();
if (name.startsWith("com.huawei.powergenie")) {
return "LocationManagerService";
} else if (name.startsWith("com.evenwell.powermonitor")) {
return "AudioIn";
}
}
return ctx.getPackageName();
}
}

View File

@@ -0,0 +1,100 @@
package org.briarproject.bramble.util;
import android.os.PowerManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
@ThreadSafe
@NotNullByDefault
public class RenewableWakeLock {
private static final Logger LOG =
Logger.getLogger(RenewableWakeLock.class.getName());
/**
* Automatically release the lock this many milliseconds after it's due
* to have been replaced and released.
*/
private static final int SAFETY_MARGIN_MS = 10_000;
private final PowerManager powerManager;
private final ScheduledExecutorService scheduler;
private final int levelAndFlags;
private final String tag;
private final long durationMs;
private final Runnable renewTask;
private final Object lock = new Object();
@Nullable
private PowerManager.WakeLock wakeLock; // Locking: lock
@Nullable
private ScheduledFuture future; // Locking: lock
public RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduler, int levelAndFlags, String tag,
long duration, TimeUnit timeUnit) {
this.powerManager = powerManager;
this.scheduler = scheduler;
this.levelAndFlags = levelAndFlags;
this.tag = tag;
durationMs = MILLISECONDS.convert(duration, timeUnit);
renewTask = this::renew;
}
public void acquire() {
if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag);
synchronized (lock) {
if (wakeLock != null) {
LOG.info("Already acquired");
return;
}
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
}
}
private void renew() {
if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
PowerManager.WakeLock oldWakeLock = wakeLock;
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
oldWakeLock.release();
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
}
}
public void release() {
if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
if (future == null) throw new AssertionError();
future.cancel(false);
future = null;
wakeLock.release();
wakeLock = null;
}
}
}

View File

@@ -7,6 +7,7 @@ import android.content.pm.ApplicationInfo;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.logging.PersistentLogManager;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser;
@@ -15,7 +16,9 @@ import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
@@ -27,6 +30,8 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
context.mock(SharedPreferences.class, "prefs");
private final SharedPreferences defaultPrefs =
context.mock(SharedPreferences.class, "defaultPrefs");
private final PersistentLogManager logManager =
context.mock(PersistentLogManager.class);
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
@@ -40,6 +45,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
private final File testDir = getTestDirectory();
private final File keyDir = new File(testDir, "key");
private final File dbDir = new File(testDir, "db");
private final File logDir = new File(testDir, "log");
private AndroidAccountManager accountManager;
@@ -61,7 +67,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
will(returnValue(app));
}});
accountManager = new AndroidAccountManager(databaseConfig, crypto,
identityManager, prefs, app) {
identityManager, prefs, logManager, app) {
@Override
SharedPreferences getDefaultSharedPreferences() {
return defaultPrefs;
@@ -109,10 +115,15 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
will(returnValue(cacheDir));
oneOf(app).getExternalCacheDir();
will(returnValue(externalCacheDir));
oneOf(app).getDir("log", MODE_PRIVATE);
will(returnValue(logDir));
oneOf(logManager).addLogHandler(with(logDir),
with(any(Logger.class)));
}});
assertTrue(dbDir.mkdirs());
assertTrue(keyDir.mkdirs());
assertTrue(logDir.mkdirs());
assertTrue(codeCacheDir.mkdirs());
assertTrue(codeCacheFile.createNewFile());
assertTrue(libDir.mkdirs());
@@ -130,6 +141,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
assertFalse(dbDir.exists());
assertFalse(keyDir.exists());
assertFalse(logDir.exists());
assertTrue(codeCacheDir.exists());
assertTrue(codeCacheFile.exists());
assertTrue(libDir.exists());

View File

@@ -1,36 +1,33 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.tools.analytics-library:protos:27.1.1:protos-27.1.1.jar:13f77e73762e58ab372d140b3a6be6903aea9775b62dd14fbc62d4cc7069c9a4',
'com.android.tools.analytics-library:shared:27.1.1:shared-27.1.1.jar:82930a52001410e97d809930b670f4de3002286975f046b9de5f6b777b06d366',
'com.android.tools.analytics-library:tracker:27.1.1:tracker-27.1.1.jar:31bc5a00be0055bac89c9b2f34751883e987cd89e3ac1783720645c164f591d9',
'com.android.tools.build:aapt2-proto:4.1.0-alpha01-6193524:aapt2-proto-4.1.0-alpha01-6193524.jar:17e75523e1e92dd4f222c7368ee41df9e964a508232f591e265d0c499baf9dca',
'com.android.tools.build:apksig:4.1.1:apksig-4.1.1.jar:e0a69da9e5a03986d608b45bbf954ef0e6a0b3f58c1b8315bd169ec08b279e72',
'com.android.tools.build:apkzlib:4.1.1:apkzlib-4.1.1.jar:ba4b5e419b6be0130eae7f8301c3a551ad3976f487d2e0c6852ebb175ac41127',
'com.android.tools.build:builder-model:4.1.1:builder-model-4.1.1.jar:e95c99cc298ad67b8deb6ced99c51abc8f59afebedad044b1a10dde14646a4dd',
'com.android.tools.build:builder-test-api:4.1.1:builder-test-api-4.1.1.jar:464f596ab261c051c3847406748e843770dea123f6fa5fee8a9390644e709b7a',
'com.android.tools.build:builder:4.1.1:builder-4.1.1.jar:0f78d4759d2f7b57b95865522ec34596ba419b9982f3b25e3449213f9c98b80d',
'com.android.tools.build:gradle-api:4.1.1:gradle-api-4.1.1.jar:d42e6b539e4c1353ad3546e75ec8ce11a017b97481023e8ea18577eefe374358',
'com.android.tools.build:manifest-merger:27.1.1:manifest-merger-27.1.1.jar:7a45fa143687859bb2e5a961dcf6ee88094d3853de0cb543dc03dbcb0f4b554b',
'com.android.tools.ddms:ddmlib:27.1.1:ddmlib-27.1.1.jar:da6e4bd834b6a85dae8019039849d8bd96933347dfbf460df74913ddade6e40a',
'com.android.tools.external.com-intellij:intellij-core:27.1.1:intellij-core-27.1.1.jar:2591a7363c4443c59bf9f793730acafce9d6ec3076e2f46716edaf53a41b6fb6',
'com.android.tools.external.com-intellij:kotlin-compiler:27.1.1:kotlin-compiler-27.1.1.jar:5054ae770ba788f110303c65abd6b1fa28eccf52dee1274510e201b2b81885c8',
'com.android.tools.external.org-jetbrains:uast:27.1.1:uast-27.1.1.jar:54cd8f6886a9d2f5641659dd5c91f626629672cd48301f7f0bd6aad9bd448714',
'com.android.tools.layoutlib:layoutlib-api:27.1.1:layoutlib-api-27.1.1.jar:8a9a22e3b309521ea83b724e5a89cfdac6076f52d675c0e17d77b05527bc0f8c',
'com.android.tools.lint:lint-api:27.1.1:lint-api-27.1.1.jar:c1d8176094cb0478786070d40533efb578ebc53529a82f6ef5bee879bdca418b',
'com.android.tools.lint:lint-checks:27.1.1:lint-checks-27.1.1.jar:3899c91e00bd059b40c31a9ca00cd0f8303191947608735ae1b657323693fb61',
'com.android.tools.lint:lint-gradle-api:27.1.1:lint-gradle-api-27.1.1.jar:26aa89d38b9825cc73229daa82a68875801c8b8491f30497ce62aff1f206eb0d',
'com.android.tools.lint:lint-gradle:27.1.1:lint-gradle-27.1.1.jar:f7355823ead869f4d28184ba28b7a0c693b507519a2d3705bb9848a0f35b3756',
'com.android.tools.lint:lint-model:27.1.1:lint-model-27.1.1.jar:bc23c0c413bdfca59dac2cd56b870d8360d009e9ec0d365e71f774bcf127971d',
'com.android.tools.lint:lint:27.1.1:lint-27.1.1.jar:2f6038a5398a42bd591883c3f5e5894f4ec52ca1c3683bf94fa8553c1700af81',
'com.android.tools:annotations:27.1.1:annotations-27.1.1.jar:ff28c504d2acb9fd1a5ffbd97ae85cf59ee18c76927525aad250509bccf2cab1',
'com.android.tools:common:27.1.1:common-27.1.1.jar:63d9a2a9ad6d278db319f3749b9f50bdf5457ef7020074a1bebe124e714b535c',
'com.android.tools:dvlib:27.1.1:dvlib-27.1.1.jar:998a54201fc1cefee5f2399215e95c42b1f64f9e1d8f4452eb8255c68ba5440f',
'com.android.tools:repository:27.1.1:repository-27.1.1.jar:d25b74ccabf4d876903efb375e9af6fb380d8ae0445bb74bbdcc225c1e37fa1d',
'com.android.tools:sdk-common:27.1.1:sdk-common-27.1.1.jar:4473ae97d0ef7061ee1de61041d5aa97405ae08e44c09cf7bb278b42e4b97c7c',
'com.android.tools:sdklib:27.1.1:sdklib-27.1.1.jar:08e6b83961ac9724b3c1e3d0eff971f13be6701292c77914b8794480f3391250',
'com.android:signflinger:4.1.1:signflinger-4.1.1.jar:0c66825988873ec2d51057fa463f54a8f18fc7326ff4530b9da363b71e97ce60',
'com.android:zipflinger:4.1.1:zipflinger-4.1.1.jar:0a8c3e52ac13dd031236f9fb5ba4408b1d5dcd12325a05440b36da09d8881446',
'com.android.tools.analytics-library:protos:26.5.1:protos-26.5.1.jar:8dde1130725461fe827f2a343d353f2b51e8870661fc860d7d5ebddb097ead4e',
'com.android.tools.analytics-library:shared:26.5.1:shared-26.5.1.jar:ccc2f3b00ec17b11401610ba68553544fc8fc517120e84439ac6eb86b875e18d',
'com.android.tools.analytics-library:tracker:26.5.1:tracker-26.5.1.jar:3a76984c0fe2e847ca7a8b35b4780ef0447a9d1666946cb8e60466318e0ab5ae',
'com.android.tools.build:aapt2-proto:0.4.0:aapt2-proto-0.4.0.jar:fac0435e08898f89eeeb9ca236bea707155ff816c12205ced285ad53604133ca',
'com.android.tools.build:apksig:3.5.1:apksig-3.5.1.jar:1fd33e7f009a2a0da766cfeec4211a09f548034b015c289a66d75dd8a9302f4a',
'com.android.tools.build:apkzlib:3.5.1:apkzlib-3.5.1.jar:9f330167cbe973b7db407692f74f4f6453b7ffa5f2048934b06280c2ceee60fa',
'com.android.tools.build:builder-model:3.5.1:builder-model-3.5.1.jar:39ea3c82b76b6e0c9f9fa88d93e0edc1dd4a0f1dfae0ef6fbf2d451da47e5450',
'com.android.tools.build:builder-test-api:3.5.1:builder-test-api-3.5.1.jar:a1b59305584cbcaa078fdc9cfb80871012755b822dd32e8da19add6f7bbcb762',
'com.android.tools.build:builder:3.5.1:builder-3.5.1.jar:e3a8d382434c5f60990730c4719fc814e85a898a33a1e96c1df8d627d3c6eea6',
'com.android.tools.build:gradle-api:3.5.1:gradle-api-3.5.1.jar:be9b41859bace11998f66b04ed944f87e413f3ad6da3c4665587699da125addc',
'com.android.tools.build:manifest-merger:26.5.1:manifest-merger-26.5.1.jar:dcad9ecb967251f4d750f55a4204a2b400e8fbfe5cb930a1d0d5dbe10ae8bdfc',
'com.android.tools.ddms:ddmlib:26.5.1:ddmlib-26.5.1.jar:b081aef2a4ed3f4d47cae4cdb128469735f25a114e026d37123bf9ffdec742a8',
'com.android.tools.external.com-intellij:intellij-core:26.5.1:intellij-core-26.5.1.jar:20eced30adc124805bd93488d9cd9d3e33e6bf7b48e9fe5a703d4983f894d450',
'com.android.tools.external.com-intellij:kotlin-compiler:26.5.1:kotlin-compiler-26.5.1.jar:5aed762dd54875b77ae7018d97c05756ff0c5b9fd02ec595dd396ccd14cc22cb',
'com.android.tools.external.org-jetbrains:uast:26.5.1:uast-26.5.1.jar:4bc8653d6c0943f40fee963a149e36c6baa45683d2530968a13f5007e3c40740',
'com.android.tools.layoutlib:layoutlib-api:26.5.1:layoutlib-api-26.5.1.jar:88732f11396c427273e515d23042e35633f4fe4295528a99b866aa2adf0efd9c',
'com.android.tools.lint:lint-api:26.5.1:lint-api-26.5.1.jar:ec33fcd72bfaf70dd841e03fbfd93f109c2e575aec146067c606689c3972f0de',
'com.android.tools.lint:lint-checks:26.5.1:lint-checks-26.5.1.jar:a1b9607d484aaae7a71dcecdc76f8003d8239af226c776894a2cf63f9e6c60d7',
'com.android.tools.lint:lint-gradle-api:26.5.1:lint-gradle-api-26.5.1.jar:82453fd98a8394cc84ed995c04d2cd744abd1d6589403427ba7eef53115406f3',
'com.android.tools.lint:lint-gradle:26.5.1:lint-gradle-26.5.1.jar:59465b56cf7db77c656d5f8195d721c3d48b6bdd0502d774de335bfe4baff00b',
'com.android.tools.lint:lint:26.5.1:lint-26.5.1.jar:336e4b04ec6f8b0f25879131b7a7862d77df83a1879ee5b71be26128755f8e2e',
'com.android.tools:annotations:26.5.1:annotations-26.5.1.jar:2c43c82f8c59d8f7a61e3239e1a2dc9f69dc342ec09af9b7c9f69b25337c0b6e',
'com.android.tools:common:26.5.1:common-26.5.1.jar:eccfa54486ed54c4e3123cc42195d023bd0dd21bcd2f0e4868e8c6fc70f8ef6b',
'com.android.tools:dvlib:26.5.1:dvlib-26.5.1.jar:46f93ad498b4756e7d867d2fe38c38890a80e7407a4ae459e4a8c8d5c5aeacfe',
'com.android.tools:repository:26.5.1:repository-26.5.1.jar:2b3ee791aa4c3e8ce60498c161a27ca7228816fc630eed4d9f25f2f36a106dce',
'com.android.tools:sdk-common:26.5.1:sdk-common-26.5.1.jar:365f749676c3574676fd465177c8a492f340816db2b520d6ed114d3b6e77bea7',
'com.android.tools:sdklib:26.5.1:sdklib-26.5.1.jar:007da104afb27c8c682a1628023fe9ec438249c8d15ef0fd6624c5bb8e23b696',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81',
'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f',
@@ -38,30 +35,27 @@ dependencyVerification {
'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718',
'com.google.dagger:dagger:2.24:dagger-2.24.jar:550a6e46a6dfcdf1d764887b6090cea94f783327e50e5c73754f18facfc70b64',
'com.google.errorprone:error_prone_annotations:2.2.0:error_prone_annotations-2.2.0.jar:6ebd22ca1b9d8ec06d41de8d64e0596981d9607b42035f9ed374f9de271a481a',
'com.google.errorprone:error_prone_annotations:2.3.2:error_prone_annotations-2.3.2.jar:357cd6cfb067c969226c442451502aee13800a24e950fdfde77bcdb4565a668d',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26',
'com.google.guava:guava:27.0.1-jre:guava-27.0.1-jre.jar:e1c814fd04492a27c38e0317eabeaa1b3e950ec8010239e400fe90ad6c9107b4',
'com.google.guava:guava:27.1-jre:guava-27.1-jre.jar:4a5aa70cc968a4d137e599ad37553e5cfeed2265e8c193476d7119036c536fe7',
'com.google.guava:guava:28.1-jre:guava-28.1-jre.jar:30beb8b8527bd07c6e747e77f1a92122c2f29d57ce347461a4a55eb26e382da4',
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6',
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.10.0:protobuf-java-3.10.0.jar:161d7d61a8cb3970891c299578702fd079646e032329d6c2cabf998d191437c9',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:3.0.7:istack-commons-runtime-3.0.7.jar:6443e10ba2e259fb821d9b6becf10db5316285fc30c53cec9d7b19a3877e7fdf',
'com.sun.xml.fastinfoset:FastInfoset:1.2.15:FastInfoset-1.2.15.jar:785861db11ca1bd0d1956682b974ad73eb19cd3e01a4b3fa82d62eca97210aec',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569',
'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.activation:javax.activation-api:1.2.0:javax.activation-api-1.2.0.jar:43fdef0b5b6ceb31b0424b208b930c74ab58fac2ceeb7b3f6fd3aeb8b5ca4393',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.3.1:jaxb-api-2.3.1.jar:88b955a0df57880a26a74708bc34f74dcaf8ebf4e78843a28b50eae945732b06',
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
@@ -75,36 +69,35 @@ dependencyVerification {
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:obfs4proxy-android:0.0.12-dev-40245c4a:obfs4proxy-android-0.0.12-dev-40245c4a.zip:8ab05a8f8391be2cb5ab2b665c281a06d9e3a756bd0f95a40a36ca927866ea82',
'org.briarproject:tor-android:0.3.5.13:tor-android-0.3.5.13.zip:e0978db136731dae07774b722970cdae1e462fb5adc82845dd80a7e2d87f356c',
'org.briarproject:obfs4proxy-android:0.0.11-2:obfs4proxy-android-0.0.11-2.zip:57e55cbe87aa2aac210fdbb6cd8cdeafe15f825406a08ebf77a8b787aa2c6a8a',
'org.briarproject:tor-android:0.3.5.10:tor-android-0.3.5.10.zip:edd83bf557fcff2105eaa0bdb3f607a6852ebe7360920929ae3039dd5f4774c5',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.checkerframework:checker-qual:2.8.1:checker-qual-2.8.1.jar:9103499008bcecd4e948da29b17864abb64304e15706444ae209d17ebe0575df',
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53',
'org.codehaus.mojo:animal-sniffer-annotations:1.18:animal-sniffer-annotations-1.18.jar:47f05852b48ee9baefef80fa3d8cea60efa4753c0013121dd7fe5eef2e5c729d',
'org.glassfish.jaxb:jaxb-runtime:2.3.1:jaxb-runtime-2.3.1.jar:45fecfa5c8217ce1f3652ab95179790ec8cc0dec0384bca51cbeb94a293d9f2f',
'org.glassfish.jaxb:txw2:2.3.1:txw2-2.3.1.jar:34975dde1c6920f1a39791142235689bc3cd357e24d05edd8ff93b885bd68d60',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jetbrains.kotlin:kotlin-reflect:1.3.72:kotlin-reflect-1.3.72.jar:a188d9367de1c4ee9479db630985c0597b20709c83161b1430d24edb27e38c40',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72:kotlin-stdlib-common-1.3.72.jar:5e7d1552863e480c1628b1cc39ce230ef829f5b7230106215a05acda5172203a',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72:kotlin-stdlib-jdk7-1.3.72.jar:40566c0c08d414b9413ba556ff7f8a0b04b98b9f0f424d122dd2088510efccc4',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72:kotlin-stdlib-jdk8-1.3.72.jar:133da70cfc07b56094282eac5c59bccd59f167ee2ead22e5282876d8bc10bf95',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.72:kotlin-stdlib-1.3.72.jar:3856a7349ebacd6d1be6802b2fed9c4dc2c5a564ea92b6b945ac988243d4b16b',
'org.jetbrains.kotlin:kotlin-reflect:1.3.50:kotlin-reflect-1.3.50.jar:64583199ea5a54aefd1bd1595288925f784226ee562d1dd279011c6075b3d7a4',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50:kotlin-stdlib-common-1.3.50.jar:8ce678e88e4ba018b66dacecf952471e4d7dfee156a8a819760a5a5ff29d323c',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50:kotlin-stdlib-jdk7-1.3.50.jar:9a026639e76212f8d57b86d55b075394c2e009f1979110751d34c05c5f75d57b',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50:kotlin-stdlib-jdk8-1.3.50.jar:1b351fb6e09c14b55525c74c1f4cf48942eae43c348b7bc764a5e6e423d4da0c',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.50:kotlin-stdlib-1.3.50.jar:e6f05746ee0366d0b52825a090fac474dcf44082c9083bbb205bd16976488d6c',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.jvnet.staxex:stax-ex:1.8:stax-ex-1.8.jar:95b05d9590af4154c6513b9c5dc1fb2e55b539972ba0a9ef28e9a0c01d83ad77',
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-analysis:7.0:asm-analysis-7.0.jar:e981f8f650c4d900bb033650b18e122fa6b161eadd5f88978d08751f72ee8474',
'org.ow2.asm:asm-commons:7.0:asm-commons-7.0.jar:fed348ef05958e3e846a3ac074a12af5f7936ef3d21ce44a62c4fa08a771927d',
'org.ow2.asm:asm-tree:7.0:asm-tree-7.0.jar:cfd7a0874f9de36a999c127feeadfbfe6e04d4a71ee954d7af3d853f0be48a6c',
'org.ow2.asm:asm-util:7.0:asm-util-7.0.jar:75fbbca440ef463f41c2b0ab1a80abe67e910ac486da60a7863cbcb5bae7e145',
'org.ow2.asm:asm-analysis:6.0:asm-analysis-6.0.jar:2f1a6387219c3a6cc4856481f221b03bd9f2408a326d416af09af5d6f608c1f4',
'org.ow2.asm:asm-commons:6.0:asm-commons-6.0.jar:f1bce5c648a96a017bdcd01fe5d59af9845297fd7b79b81c015a6fbbd9719abf',
'org.ow2.asm:asm-tree:6.0:asm-tree-6.0.jar:887998fb69727c8759e4d253f856822801e33f9fd4caa566b3ac58ee92106215',
'org.ow2.asm:asm-util:6.0:asm-util-6.0.jar:356afebdb0f870175262e5188f8709a3b17aa2a5a6a4b0340b04d4b449bca5f6',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.ow2.asm:asm:7.0:asm-7.0.jar:b88ef66468b3c978ad0c97fd6e90979e56155b4ac69089ba7a44e9aa7ffe9acf',
'org.ow2.asm:asm:6.0:asm-6.0.jar:dd8971c74a4e697899a8e95caae4ea8760ea6c486dc6b97b1795e75760420461',
]
}

View File

@@ -6,10 +6,4 @@ package org.briarproject.bramble.api;
public interface FeatureFlags {
boolean shouldEnableImageAttachments();
boolean shouldEnableProfilePictures();
boolean shouldEnableDisappearingMessages();
boolean shouldEnableConnectViaBluetooth();
}

View File

@@ -1,8 +1,16 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Hashtable;
import java.util.Map;
import javax.annotation.Nullable;
import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@NotNullByDefault
public abstract class StringMap extends Hashtable<String, String> {
protected StringMap(Map<String, String> m) {
@@ -52,4 +60,19 @@ public abstract class StringMap extends Hashtable<String, String> {
public void putLong(String key, long value) {
put(key, String.valueOf(value));
}
@Nullable
public byte[] getBytes(String key) {
String s = get(key);
if (s == null) return null;
try {
return fromHexString(s);
} catch (IllegalArgumentException e) {
return null;
}
}
public void putBytes(String key, byte[] value) {
put(key, toHexString(value));
}
}

View File

@@ -1,29 +0,0 @@
package org.briarproject.bramble.api.cleanup;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import java.util.Collection;
/**
* An interface for registering a hook with the {@link CleanupManager}
* that will be called when a message's cleanup deadline is reached.
*/
@NotNullByDefault
public interface CleanupHook {
/**
* Called when the cleanup deadlines of one or more messages are reached.
* <p>
* The callee is not required to delete the messages, but the hook won't be
* called again for these messages unless another cleanup timer is set (see
* {@link DatabaseComponent#setCleanupTimerDuration(Transaction, MessageId, long)}
* and {@link DatabaseComponent#startCleanupTimer(Transaction, MessageId)}).
*/
void deleteMessages(Transaction txn, GroupId g,
Collection<MessageId> messageIds) throws DbException;
}

View File

@@ -1,42 +0,0 @@
package org.briarproject.bramble.api.cleanup;
import org.briarproject.bramble.api.cleanup.event.CleanupTimerStartedEvent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.MessageId;
/**
* The CleanupManager is responsible for tracking the cleanup deadlines of
* messages and passing them to their respective
* {@link CleanupHook CleanupHooks} when the deadlines are reached.
* <p>
* The CleanupManager responds to
* {@link CleanupTimerStartedEvent CleanupTimerStartedEvents} broadcast by the
* {@link DatabaseComponent}.
* <p>
* See {@link DatabaseComponent#setCleanupTimerDuration(Transaction, MessageId, long)},
* {@link DatabaseComponent#startCleanupTimer(Transaction, MessageId)},
* {@link DatabaseComponent#stopCleanupTimer(Transaction, MessageId)}.
*/
@NotNullByDefault
public interface CleanupManager {
/**
* When scheduling a cleanup task we overshoot the deadline by this many
* milliseconds to reduce the number of tasks that need to be scheduled
* when messages have cleanup deadlines that are close together.
*/
long BATCH_DELAY_MS = 1000;
/**
* Registers a hook to be called when messages are due for cleanup.
* This method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerCleanupHook(ClientId c, int majorVersion,
CleanupHook hook);
}

View File

@@ -1,32 +0,0 @@
package org.briarproject.bramble.api.cleanup.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a message's cleanup timer is started.
*/
@Immutable
@NotNullByDefault
public class CleanupTimerStartedEvent extends Event {
private final MessageId messageId;
private final long cleanupDeadline;
public CleanupTimerStartedEvent(MessageId messageId,
long cleanupDeadline) {
this.messageId = messageId;
this.cleanupDeadline = cleanupDeadline;
}
public MessageId getMessageId() {
return messageId;
}
public long getCleanupDeadline() {
return cleanupDeadline;
}
}

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary;
@@ -17,7 +16,6 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.Map;
@NotNullByDefault
@@ -52,11 +50,9 @@ public interface ClientHelper {
BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g)
throws DbException, FormatException;
Collection<MessageId> getMessageIds(Transaction txn, GroupId g,
BdfDictionary query) throws DbException, FormatException;
BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException;
throws DbException,
FormatException;
BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m)
throws DbException, FormatException;
@@ -123,17 +119,4 @@ public interface ClientHelper {
Map<TransportId, TransportProperties> parseAndValidateTransportPropertiesMap(
BdfDictionary properties) throws FormatException;
/**
* Retrieves the contact ID from the group metadata of the given contact
* group.
*/
ContactId getContactId(Transaction txn, GroupId contactGroupId)
throws DbException, FormatException;
/**
* Stores the given contact ID in the group metadata of the given contact
* group.
*/
void setContactId(Transaction txn, GroupId contactGroupId, ContactId c)
throws DbException;
}

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.client;
public interface ContactGroupConstants {
/**
* Group metadata key for associating a contact ID with a contact group.
*/
String GROUP_KEY_CONTACT_ID = "contactId";
}

View File

@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.db.PendingContactExistsException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -178,11 +179,6 @@ public interface ContactManager {
*/
Collection<Contact> getContacts() throws DbException;
/**
* Returns all contacts.
*/
Collection<Contact> getContacts(Transaction txn) throws DbException;
/**
* Removes a contact and all associated state.
*/
@@ -219,6 +215,16 @@ public interface ContactManager {
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(AuthorId a) throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(Transaction txn, AuthorId a) throws DbException;
interface ContactHook {
/**

View File

@@ -1,35 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when the alias for a contact changed.
*/
@Immutable
@NotNullByDefault
public class ContactAliasChangedEvent extends Event {
private final ContactId contactId;
@Nullable
private final String alias;
public ContactAliasChangedEvent(ContactId contactId,
@Nullable String alias) {
this.contactId = contactId;
this.alias = alias;
}
public ContactId getContactId() {
return contactId;
}
@Nullable
public String getAlias() {
return alias;
}
}

View File

@@ -41,18 +41,6 @@ import javax.annotation.Nullable;
@NotNullByDefault
public interface DatabaseComponent extends TransactionManager {
/**
* Return value for {@link #getNextCleanupDeadline(Transaction)} if
* no messages are scheduled to be deleted.
*/
long NO_CLEANUP_DEADLINE = -1;
/**
* Return value for {@link #startCleanupTimer(Transaction, MessageId)}
* if the cleanup timer was not started.
*/
long TIMER_NOT_STARTED = -1;
/**
* Opens the database and returns true if the database already existed.
*
@@ -300,16 +288,6 @@ public interface DatabaseComponent extends TransactionManager {
Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
throws DbException;
/**
* Returns the IDs of any delivered messages in the given group with
* metadata that matches all entries in the given query. If the query is
* empty, the IDs of all delivered messages are returned.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessageIds(Transaction txn, GroupId g,
Metadata query) throws DbException;
/**
* Returns the IDs of any messages that need to be validated.
* <p/>
@@ -336,15 +314,6 @@ public interface DatabaseComponent extends TransactionManager {
Collection<MessageId> getMessagesToShare(Transaction txn)
throws DbException;
/**
* Returns the IDs of any messages of any messages that are due for
* deletion, along with their group IDs.
* <p/>
* Read-only.
*/
Map<GroupId, Collection<MessageId>> getMessagesToDelete(Transaction txn)
throws DbException;
/**
* Returns the metadata for all delivered messages in the given group.
* <p/>
@@ -426,15 +395,6 @@ public interface DatabaseComponent extends TransactionManager {
MessageStatus getMessageStatus(Transaction txn, ContactId c, MessageId m)
throws DbException;
/**
* Returns the next time (in milliseconds since the Unix epoch) when a
* message is due to be deleted, or {@link #NO_CLEANUP_DEADLINE}
* if no messages are scheduled to be deleted.
* <p/>
* Read-only.
*/
long getNextCleanupDeadline(Transaction txn) throws DbException;
/*
* Returns the next time (in milliseconds since the Unix epoch) when a
* message is due to be sent to the given contact. The returned value may
@@ -575,13 +535,6 @@ public interface DatabaseComponent extends TransactionManager {
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/**
* Sets the cleanup timer duration for the given message. This does not
* start the message's cleanup timer.
*/
void setCleanupTimerDuration(Transaction txn, MessageId m, long duration)
throws DbException;
/**
* Marks the given contact as verified.
*/
@@ -604,12 +557,6 @@ public interface DatabaseComponent extends TransactionManager {
*/
void setMessagePermanent(Transaction txn, MessageId m) throws DbException;
/**
* Marks the given message as not shared. This method is only meant for
* testing.
*/
void setMessageNotShared(Transaction txn, MessageId m) throws DbException;
/**
* Marks the given message as shared.
*/
@@ -652,22 +599,6 @@ public interface DatabaseComponent extends TransactionManager {
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/**
* Starts the cleanup timer for the given message, if a timer duration
* has been set and the timer has not already been started.
*
* @return The cleanup deadline, or {@link #TIMER_NOT_STARTED} if no
* timer duration has been set for this message or its timer has already
* been started.
*/
long startCleanupTimer(Transaction txn, MessageId m) throws DbException;
/**
* Stops the cleanup timer for the given message, if the timer has been
* started.
*/
void stopCleanupTimer(Transaction txn, MessageId m) throws DbException;
/**
* Stores the given transport keys, deleting any keys they have replaced.
*/

View File

@@ -57,7 +57,6 @@ public class Author implements Nameable {
/**
* Returns the author's name.
*/
@Override
public String getName() {
return name;
}

View File

@@ -1,8 +1,6 @@
package org.briarproject.briar.api.identity;
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NullSafety;
import org.briarproject.briar.api.attachment.AttachmentHeader;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@@ -22,18 +20,14 @@ public class AuthorInfo {
private final Status status;
@Nullable
private final String alias;
@Nullable
private final AttachmentHeader avatarHeader;
public AuthorInfo(Status status, @Nullable String alias,
@Nullable AttachmentHeader avatarHeader) {
public AuthorInfo(Status status, @Nullable String alias) {
this.status = status;
this.alias = alias;
this.avatarHeader = avatarHeader;
}
public AuthorInfo(Status status) {
this(status, null, null);
this(status, null);
}
public Status getStatus() {
@@ -45,11 +39,6 @@ public class AuthorInfo {
return alias;
}
@Nullable
public AttachmentHeader getAvatarHeader() {
return avatarHeader;
}
@Override
public int hashCode() {
int hashCode = status.ordinal();
@@ -62,9 +51,6 @@ public class AuthorInfo {
if (!(o instanceof AuthorInfo)) return false;
AuthorInfo info = (AuthorInfo) o;
return status == info.status &&
// aliases are equal
NullSafety.equals(alias, info.alias) &&
// avatars are equal
NullSafety.equals(avatarHeader, info.avatarHeader);
(alias == null ? info.alias == null : alias.equals(info.alias));
}
}

View File

@@ -7,10 +7,6 @@ public interface TimeoutMonitor {
/**
* Returns an {@link InputStream} that wraps the given stream and allows
* read timeouts to be detected.
* <p>
* The returned stream must be {@link InputStream#close() closed} when it's
* no longer needed to ensure that resources held by the timeout monitor
* are released.
*
* @param timeoutMs The read timeout in milliseconds. Timeouts will be
* detected eventually but are not guaranteed to be detected immediately.

View File

@@ -3,7 +3,7 @@ package org.briarproject.bramble.api.keyagreement.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when a BQP protocol begins.
* An event that is broadcast when a BQP protocol completes.
*/
public class KeyAgreementStartedEvent extends Event {
}

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.Wakeful;
import java.util.concurrent.ExecutorService;
@@ -66,7 +65,6 @@ public interface LifecycleManager {
* Opens the {@link DatabaseComponent} using the given key and starts any
* registered {@link Service Services}.
*/
@Wakeful
StartResult startServices(SecretKey dbKey);
/**
@@ -74,7 +72,6 @@ public interface LifecycleManager {
* registered {@link ExecutorService ExecutorServices}, and closes the
* {@link DatabaseComponent}.
*/
@Wakeful
void stopServices();
/**
@@ -107,7 +104,6 @@ public interface LifecycleManager {
*
* @param txn A read-write transaction
*/
@Wakeful
void onDatabaseOpened(Transaction txn) throws DbException;
}
}

View File

@@ -1,20 +1,16 @@
package org.briarproject.bramble.api.lifecycle;
import org.briarproject.bramble.api.system.Wakeful;
public interface Service {
/**
* Starts the service. This method must not be called concurrently with
* Starts the service.This method must not be called concurrently with
* {@link #stopService()}.
*/
@Wakeful
void startService() throws ServiceException;
/**
* Stops the service. This method must not be called concurrently with
* {@link #startService()}.
*/
@Wakeful
void stopService() throws ServiceException;
}

View File

@@ -0,0 +1,46 @@
package org.briarproject.bramble.api.logging;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.settings.Settings;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.logging.Handler;
import java.util.logging.Logger;
@NotNullByDefault
public interface PersistentLogManager {
/**
* The namespace of the (@link Settings) where the log key is stored.
*/
String LOG_SETTINGS_NAMESPACE = "log";
/**
* The {@link Settings} key under which the log key is stored.
*/
String LOG_KEY_KEY = "logKey";
/**
* Creates and returns a persistent log handler that stores its logs in
* the given directory.
*/
Handler createLogHandler(File dir) throws IOException;
/**
* Creates a persistent log handler that stores its logs in the given
* directory and adds the handler to the given logger, replacing any
* existing persistent log handler.
*/
void addLogHandler(File dir, Logger logger) throws IOException;
/**
* Returns a {@link Scanner} for reading the persistent log entries stored
* in the given directory.
*
* @param old True if the previous session's log should be loaded, or false
* if the current session's log should be loaded
*/
Scanner getPersistedLog(File dir, boolean old) throws IOException;
}

View File

@@ -8,12 +8,11 @@ import javax.annotation.concurrent.Immutable;
@NotNullByDefault
public class NetworkStatus {
private final boolean connected, wifi, ipv6Only;
private final boolean connected, wifi;
public NetworkStatus(boolean connected, boolean wifi, boolean ipv6Only) {
public NetworkStatus(boolean connected, boolean wifi) {
this.connected = connected;
this.wifi = wifi;
this.ipv6Only = ipv6Only;
}
public boolean isConnected() {
@@ -23,8 +22,4 @@ public class NetworkStatus {
public boolean isWifi() {
return wifi;
}
public boolean isIpv6Only() {
return ipv6Only;
}
}

View File

@@ -29,12 +29,4 @@ public class NullSafety {
public static void requireNull(@Nullable Object o) {
if (o != null) throw new AssertionError();
}
/**
* Stand-in for {@code Objects.equals()}.
*/
public static boolean equals(@Nullable Object a, @Nullable Object b) {
return (a == b) || (a != null && a.equals(b));
}
}

View File

@@ -10,12 +10,6 @@ public interface BluetoothConstants {
String PROP_ADDRESS = "address";
String PROP_UUID = "uuid";
// Local settings (not shared with contacts)
String PREF_ADDRESS_IS_REFLECTED = "addressIsReflected";
String PREF_EVER_CONNECTED = "everConnected";
// Default values for local settings
// Default value for PREF_PLUGIN_ENABLE
boolean DEFAULT_PREF_PLUGIN_ENABLE = false;
boolean DEFAULT_PREF_ADDRESS_IS_REFLECTED = false;
boolean DEFAULT_PREF_EVER_CONNECTED = false;
}

View File

@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.system.Wakeful;
import java.util.Collection;
@@ -71,13 +70,11 @@ public interface Plugin {
/**
* Starts the plugin.
*/
@Wakeful
void start() throws PluginException;
/**
* Stops the plugin.
*/
@Wakeful
void stop() throws PluginException;
/**
@@ -109,7 +106,6 @@ public interface Plugin {
* Attempts to create connections using the given transport properties,
* passing any created connections to the corresponding handlers.
*/
@Wakeful
void poll(Collection<Pair<TransportProperties, ConnectionHandler>>
properties);
}

View File

@@ -8,8 +8,6 @@ import org.briarproject.bramble.api.plugin.event.TransportStateEvent;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import java.util.Collection;
/**
* An interface through which a transport plugin interacts with the rest of
* the application.
@@ -27,11 +25,6 @@ public interface PluginCallback extends ConnectionHandler {
*/
TransportProperties getLocalProperties();
/**
* Returns the plugin's remote transport properties.
*/
Collection<TransportProperties> getRemoteProperties();
/**
* Merges the given settings with the plugin's settings
*/

View File

@@ -1,7 +1,5 @@
package org.briarproject.bramble.api.plugin;
import static java.util.concurrent.TimeUnit.DAYS;
public interface TorConstants {
TransportId ID = new TransportId("org.briarproject.bramble.tor");
@@ -21,14 +19,6 @@ public interface TorConstants {
String PREF_TOR_PORT = "port";
String PREF_TOR_MOBILE = "useMobileData";
String PREF_TOR_ONLY_WHEN_CHARGING = "onlyWhenCharging";
String HS_PRIVATE_KEY_V2 = "onionPrivKey";
String HS_PRIVATE_KEY_V3 = "onionPrivKey3";
String HS_V3_CREATED = "onionPrivKey3Created";
/**
* How long to publish a v3 hidden service before retiring the v2 service.
*/
long V3_MIGRATION_PERIOD_MS = DAYS.toMillis(180);
// Values for PREF_TOR_NETWORK
int PREF_TOR_NETWORK_AUTOMATIC = 0;

View File

@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
import org.briarproject.bramble.api.system.Wakeful;
import javax.annotation.Nullable;
@@ -22,7 +21,6 @@ public interface DuplexPlugin extends Plugin {
* Attempts to create and return a connection using the given transport
* properties. Returns null if a connection cannot be created.
*/
@Wakeful
@Nullable
DuplexTransportConnection createConnection(TransportProperties p);

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that informs the Bluetooth plugin that we have enabled the
* Bluetooth adapter.
*/
@Immutable
@NotNullByDefault
public class BluetoothEnabledEvent extends Event {
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that asks the Bluetooth plugin to disable the Bluetooth adapter if
* we previously enabled it.
*/
@Immutable
@NotNullByDefault
public class DisableBluetoothEvent extends Event {
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that asks the Bluetooth plugin to enable the Bluetooth adapter.
*/
@Immutable
@NotNullByDefault
public class EnableBluetoothEvent extends Event {
}

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.system.Wakeful;
import javax.annotation.Nullable;
@@ -19,7 +18,6 @@ public interface SimplexPlugin extends Plugin {
* Attempts to create and return a reader for the given transport
* properties. Returns null if a reader cannot be created.
*/
@Wakeful
@Nullable
TransportConnectionReader createReader(TransportProperties p);
@@ -27,7 +25,6 @@ public interface SimplexPlugin extends Plugin {
* Attempts to create and return a writer for the given transport
* properties. Returns null if a writer cannot be created.
*/
@Wakeful
@Nullable
TransportConnectionWriter createWriter(TransportProperties p);
}

View File

@@ -12,11 +12,6 @@ public interface TransportPropertyConstants {
*/
int MAX_PROPERTY_LENGTH = 100;
/**
* Prefix for keys that represent reflected properties.
*/
String REFLECTED_PROPERTY_PREFIX = "u:";
/**
* Message metadata key for the transport ID of a local or remote update,
* as a BDF string.

View File

@@ -1,27 +0,0 @@
package org.briarproject.bramble.api.properties.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when {@link TransportProperties} are received
* from a contact.
*/
@Immutable
@NotNullByDefault
public class RemoteTransportPropertiesUpdatedEvent extends Event {
private final TransportId transportId;
public RemoteTransportPropertiesUpdatedEvent(TransportId transportId) {
this.transportId = transportId;
}
public TransportId getTransportId() {
return transportId;
}
}

View File

@@ -13,6 +13,4 @@ public interface DevConfig {
String getDevOnionAddress();
File getReportDir();
File getLogcatFile();
}

View File

@@ -23,8 +23,6 @@ public interface DevReporter {
/**
* Sends any reports previously stored on disk.
*
* @return The number of reports that were sent.
*/
int sendReports();
void sendReports();
}

View File

@@ -21,6 +21,5 @@ public interface ReportingConstants {
* Hidden service address for reporting crashes and feedback to the
* developers.
*/
String DEV_ONION_ADDRESS =
"b2nkt5doeamvdmjzfz7g42hk5vdtlnktlgzhel2bgjcc4v4jhnx2qrqd.onion";
String DEV_ONION_ADDRESS = "cwqmubyvnig3wag3.onion";
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.api.plugin;
package org.briarproject.bramble.api.system;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -12,11 +11,15 @@ import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the {@link File directory} where the Tor plugin
* should store its state.
* Annotation for injecting a scheduled executor service
* that can be used to schedule the execution of tasks.
* <p>
* The service should <b>only</b> be used for running tasks on other executors
* at scheduled times.
* No significant work should be run by the service itself!
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface TorDirectory {
}
public @interface Scheduler {
}

View File

@@ -1,43 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
* A service that can be used to schedule the execution of tasks.
*/
@NotNullByDefault
public interface TaskScheduler {
/**
* Submits the given task to the given executor after the given delay.
* <p>
* If the platform supports wake locks, a wake lock will be held while
* submitting and running the task.
*/
Cancellable schedule(Runnable task, Executor executor, long delay,
TimeUnit unit);
/**
* Submits the given task to the given executor after the given delay,
* and then repeatedly with the given interval between executions
* (measured from the end of one execution to the beginning of the next).
* <p>
* If the platform supports wake locks, a wake lock will be held while
* submitting and running the task.
*/
Cancellable scheduleWithFixedDelay(Runnable task, Executor executor,
long delay, long interval, TimeUnit unit);
interface Cancellable {
/**
* Cancels the task if it has not already started running. If the task
* is {@link #scheduleWithFixedDelay(Runnable, Executor, long, long, TimeUnit) periodic},
* all future executions of the task are cancelled.
*/
void cancel();
}
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.system;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for methods that must be called while holding a wake lock, if
* the platform supports wake locks.
*/
@Qualifier
@Target(METHOD)
@Retention(RUNTIME)
public @interface Wakeful {
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api.system;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the executor for long-running IO tasks that should
* run without sleeping. Also used for annotating methods that should run on
* this executor.
* <p>
* The contract of this executor is that tasks may be run concurrently, and
* submitting a task will never block. Tasks must not run indefinitely. Tasks
* submitted during shutdown are discarded.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface WakefulIoExecutor {
}

View File

@@ -7,6 +7,7 @@ import java.io.OutputStream;
@NotNullByDefault
public interface StreamWriterFactory {
/**
* Creates a {@link StreamWriter} for writing to a transport stream.
*/

View File

@@ -6,9 +6,7 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class ValidationUtils {
@@ -66,9 +64,4 @@ public class ValidationUtils {
if (dictionary != null && dictionary.size() != size)
throw new FormatException();
}
public static void checkRange(@Nullable Long l, long min, long max)
throws FormatException {
if (l != null && (l < min || l > max)) throw new FormatException();
}
}

View File

@@ -0,0 +1,42 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.NONE;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
public class AuthorInfoTest extends BrambleTestCase {
@Test
public void testEquals() {
assertEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, null)
);
assertEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(VERIFIED)
);
assertNotEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE)
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE, "a"),
new AuthorInfo(NONE, "b")
);
}
}

View File

@@ -1,8 +0,0 @@
package org.briarproject.bramble.test;
public interface TimeTravel {
void setCurrentTimeMillis(long now) throws InterruptedException;
void addCurrentTimeMillis(long add) throws InterruptedException;
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble;
import org.briarproject.bramble.cleanup.CleanupModule;
import org.briarproject.bramble.contact.ContactModule;
import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.db.DatabaseExecutorModule;
@@ -10,13 +9,12 @@ import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.rendezvous.RendezvousModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule;
public interface BrambleCoreEagerSingletons {
void inject(CleanupModule.EagerSingletons init);
void inject(ContactModule.EagerSingletons init);
void inject(CryptoExecutorModule.EagerSingletons init);
@@ -33,6 +31,8 @@ public interface BrambleCoreEagerSingletons {
void inject(RendezvousModule.EagerSingletons init);
void inject(SystemModule.EagerSingletons init);
void inject(TransportModule.EagerSingletons init);
void inject(ValidationModule.EagerSingletons init);
@@ -42,7 +42,6 @@ public interface BrambleCoreEagerSingletons {
class Helper {
public static void injectEagerSingletons(BrambleCoreEagerSingletons c) {
c.inject(new CleanupModule.EagerSingletons());
c.inject(new ContactModule.EagerSingletons());
c.inject(new CryptoExecutorModule.EagerSingletons());
c.inject(new DatabaseExecutorModule.EagerSingletons());
@@ -51,6 +50,7 @@ public interface BrambleCoreEagerSingletons {
c.inject(new RendezvousModule.EagerSingletons());
c.inject(new PluginModule.EagerSingletons());
c.inject(new PropertiesModule.EagerSingletons());
c.inject(new SystemModule.EagerSingletons());
c.inject(new TransportModule.EagerSingletons());
c.inject(new ValidationModule.EagerSingletons());
c.inject(new VersioningModule.EagerSingletons());

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble;
import org.briarproject.bramble.cleanup.CleanupModule;
import org.briarproject.bramble.client.ClientModule;
import org.briarproject.bramble.connection.ConnectionModule;
import org.briarproject.bramble.contact.ContactModule;
@@ -14,6 +13,7 @@ import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.io.IoModule;
import org.briarproject.bramble.keyagreement.KeyAgreementModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
import org.briarproject.bramble.logging.LoggingModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.record.RecordModule;
@@ -22,13 +22,13 @@ import org.briarproject.bramble.rendezvous.RendezvousModule;
import org.briarproject.bramble.settings.SettingsModule;
import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule;
import dagger.Module;
@Module(includes = {
CleanupModule.class,
ClientModule.class,
ConnectionModule.class,
ContactModule.class,
@@ -42,6 +42,7 @@ import dagger.Module;
IoModule.class,
KeyAgreementModule.class,
LifecycleModule.class,
LoggingModule.class,
PluginModule.class,
PropertiesModule.class,
RecordModule.class,
@@ -49,6 +50,7 @@ import dagger.Module;
RendezvousModule.class,
SettingsModule.class,
SyncModule.class,
SystemModule.class,
TransportModule.class,
ValidationModule.class,
VersioningModule.class

View File

@@ -1,159 +0,0 @@
package org.briarproject.bramble.cleanup;
import org.briarproject.bramble.api.cleanup.CleanupHook;
import org.briarproject.bramble.api.cleanup.CleanupManager;
import org.briarproject.bramble.api.cleanup.event.CleanupTimerStartedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.lang.Math.max;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.db.DatabaseComponent.NO_CLEANUP_DEADLINE;
import static org.briarproject.bramble.util.LogUtils.logException;
@ThreadSafe
@NotNullByDefault
class CleanupManagerImpl implements CleanupManager, Service, EventListener {
private static final Logger LOG =
getLogger(CleanupManagerImpl.class.getName());
private final Executor dbExecutor;
private final DatabaseComponent db;
private final TaskScheduler taskScheduler;
private final Clock clock;
private final Map<ClientMajorVersion, CleanupHook> hooks =
new ConcurrentHashMap<>();
private final Object lock = new Object();
@GuardedBy("lock")
private final Set<CleanupTask> pending = new HashSet<>();
@Inject
CleanupManagerImpl(@DatabaseExecutor Executor dbExecutor,
DatabaseComponent db, TaskScheduler taskScheduler, Clock clock) {
this.dbExecutor = dbExecutor;
this.db = db;
this.taskScheduler = taskScheduler;
this.clock = clock;
}
@Override
public void registerCleanupHook(ClientId c, int majorVersion,
CleanupHook hook) {
hooks.put(new ClientMajorVersion(c, majorVersion), hook);
}
@Override
public void startService() {
maybeScheduleTask(clock.currentTimeMillis());
}
@Override
public void stopService() {
}
@Override
public void eventOccurred(Event e) {
if (e instanceof CleanupTimerStartedEvent) {
CleanupTimerStartedEvent a = (CleanupTimerStartedEvent) e;
maybeScheduleTask(a.getCleanupDeadline());
}
}
private void maybeScheduleTask(long deadline) {
synchronized (lock) {
for (CleanupTask task : pending) {
if (task.deadline <= deadline) return;
}
CleanupTask task = new CleanupTask(deadline);
pending.add(task);
scheduleTask(task);
}
}
private void scheduleTask(CleanupTask task) {
long now = clock.currentTimeMillis();
long delay = max(0, task.deadline - now + BATCH_DELAY_MS);
if (LOG.isLoggable(INFO)) {
LOG.info("Scheduling cleanup task in " + delay + " ms");
}
taskScheduler.schedule(() -> deleteMessagesAndScheduleNextTask(task),
dbExecutor, delay, MILLISECONDS);
}
private void deleteMessagesAndScheduleNextTask(CleanupTask task) {
try {
synchronized (lock) {
pending.remove(task);
}
long deadline = db.transactionWithResult(false, txn -> {
deleteMessages(txn);
return db.getNextCleanupDeadline(txn);
});
if (deadline != NO_CLEANUP_DEADLINE) {
maybeScheduleTask(deadline);
}
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}
private void deleteMessages(Transaction txn) throws DbException {
Map<GroupId, Collection<MessageId>> ids = db.getMessagesToDelete(txn);
for (Entry<GroupId, Collection<MessageId>> e : ids.entrySet()) {
GroupId groupId = e.getKey();
Collection<MessageId> messageIds = e.getValue();
if (LOG.isLoggable(INFO)) {
LOG.info(messageIds.size() + " messages to delete");
}
for (MessageId m : messageIds) db.stopCleanupTimer(txn, m);
Group group = db.getGroup(txn, groupId);
ClientMajorVersion cv = new ClientMajorVersion(group.getClientId(),
group.getMajorVersion());
CleanupHook hook = hooks.get(cv);
if (hook == null) {
throw new IllegalStateException("No cleanup hook for " + cv);
}
hook.deleteMessages(txn, groupId, messageIds);
}
}
private static class CleanupTask {
private final long deadline;
private CleanupTask(long deadline) {
this.deadline = deadline;
}
}
}

View File

@@ -1,29 +0,0 @@
package org.briarproject.bramble.cleanup;
import org.briarproject.bramble.api.cleanup.CleanupManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class CleanupModule {
public static class EagerSingletons {
@Inject
CleanupManager cleanupManager;
}
@Provides
@Singleton
CleanupManager provideCleanupManager(LifecycleManager lifecycleManager,
EventBus eventBus, CleanupManagerImpl cleanupManager) {
lifecycleManager.registerService(cleanupManager);
eventBus.addListener(cleanupManager);
return cleanupManager;
}
}

View File

@@ -2,13 +2,11 @@ package org.briarproject.bramble.client;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyParser;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.BdfReader;
import org.briarproject.bramble.api.data.BdfReaderFactory;
@@ -34,7 +32,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -42,7 +39,6 @@ import java.util.Map.Entry;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static org.briarproject.bramble.api.client.ContactGroupConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
@@ -155,12 +151,6 @@ class ClientHelperImpl implements ClientHelper {
return metadataParser.parse(metadata);
}
@Override
public Collection<MessageId> getMessageIds(Transaction txn, GroupId g,
BdfDictionary query) throws DbException, FormatException {
return db.getMessageIds(txn, g, metadataEncoder.encode(query));
}
@Override
public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException {
@@ -399,27 +389,4 @@ class ClientHelperImpl implements ClientHelper {
return tpMap;
}
@Override
public ContactId getContactId(Transaction txn, GroupId contactGroupId)
throws DbException {
try {
BdfDictionary meta =
getGroupMetadataAsDictionary(txn, contactGroupId);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) {
throw new DbException(e); // Invalid group metadata
}
}
@Override
public void setContactId(Transaction txn, GroupId contactGroupId,
ContactId c) throws DbException {
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_CONTACT_ID, c.getInt()));
try {
mergeGroupMetadata(txn, contactGroupId, meta);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
}

View File

@@ -20,7 +20,9 @@ import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.KeyManager;
@@ -38,6 +40,10 @@ import javax.inject.Inject;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@ThreadSafe
@@ -207,11 +213,6 @@ class ContactManagerImpl implements ContactManager, EventListener {
return db.transactionWithResult(true, db::getContacts);
}
@Override
public Collection<Contact> getContacts(Transaction txn) throws DbException {
return db.getContacts(txn);
}
@Override
public void removeContact(ContactId c) throws DbException {
db.transaction(false, txn -> removeContact(txn, c));
@@ -255,6 +256,25 @@ class ContactManagerImpl implements ContactManager, EventListener {
db.removeContact(txn, c);
}
@Override
public AuthorInfo getAuthorInfo(AuthorId a) throws DbException {
return db.transactionWithResult(true, txn -> getAuthorInfo(txn, a));
}
@Override
public AuthorInfo getAuthorInfo(Transaction txn, AuthorId authorId)
throws DbException {
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
if (localAuthor.getId().equals(authorId))
return new AuthorInfo(OURSELVES);
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
if (contacts.isEmpty()) return new AuthorInfo(UNKNOWN);
if (contacts.size() > 1) throw new AssertionError();
Contact c = contacts.iterator().next();
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
else return new AuthorInfo(UNVERIFIED, c.getAlias());
}
@Override
public void eventOccurred(Event e) {
if (e instanceof PendingContactStateChangedEvent) {

Some files were not shown because too many files have changed in this diff Show More