Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
com.ccwangluo.accelerator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sheteng
com.ccwangluo.accelerator
Commits
612a34a6
Unverified
Commit
612a34a6
authored
Dec 16, 2017
by
Max Lv
Committed by
GitHub
Dec 16, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1508 from Mygod/direct-boot
Implement direct boot awareness
parents
6eec78a3
f1934f87
Changes
31
Show whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
457 additions
and
176 deletions
+457
-176
mobile/src/main/AndroidManifest.xml
mobile/src/main/AndroidManifest.xml
+25
-8
mobile/src/main/java/com/evernote/android/job/JobConstants.kt
...le/src/main/java/com/evernote/android/job/JobConstants.kt
+26
-0
mobile/src/main/java/com/github/shadowsocks/App.kt
mobile/src/main/java/com/github/shadowsocks/App.kt
+30
-16
mobile/src/main/java/com/github/shadowsocks/AppManager.kt
mobile/src/main/java/com/github/shadowsocks/AppManager.kt
+2
-0
mobile/src/main/java/com/github/shadowsocks/BootReceiver.kt
mobile/src/main/java/com/github/shadowsocks/BootReceiver.kt
+7
-1
mobile/src/main/java/com/github/shadowsocks/ConfigBackupHelper.kt
...rc/main/java/com/github/shadowsocks/ConfigBackupHelper.kt
+2
-2
mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
...om/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
+18
-5
mobile/src/main/java/com/github/shadowsocks/MainActivity.kt
mobile/src/main/java/com/github/shadowsocks/MainActivity.kt
+2
-2
mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt
...main/java/com/github/shadowsocks/ProfileConfigFragment.kt
+5
-3
mobile/src/main/java/com/github/shadowsocks/acl/Acl.kt
mobile/src/main/java/com/github/shadowsocks/acl/Acl.kt
+3
-2
mobile/src/main/java/com/github/shadowsocks/bg/BaseService.kt
...le/src/main/java/com/github/shadowsocks/bg/BaseService.kt
+20
-5
mobile/src/main/java/com/github/shadowsocks/bg/Executable.kt
mobile/src/main/java/com/github/shadowsocks/bg/Executable.kt
+1
-2
mobile/src/main/java/com/github/shadowsocks/bg/GuardedProcess.kt
...src/main/java/com/github/shadowsocks/bg/GuardedProcess.kt
+1
-1
mobile/src/main/java/com/github/shadowsocks/bg/LocalDnsService.kt
...rc/main/java/com/github/shadowsocks/bg/LocalDnsService.kt
+1
-1
mobile/src/main/java/com/github/shadowsocks/bg/TrafficMonitorThread.kt
...in/java/com/github/shadowsocks/bg/TrafficMonitorThread.kt
+1
-1
mobile/src/main/java/com/github/shadowsocks/bg/TransproxyService.kt
.../main/java/com/github/shadowsocks/bg/TransproxyService.kt
+5
-5
mobile/src/main/java/com/github/shadowsocks/bg/VpnService.kt
mobile/src/main/java/com/github/shadowsocks/bg/VpnService.kt
+2
-2
mobile/src/main/java/com/github/shadowsocks/database/PrivateDatabase.kt
...n/java/com/github/shadowsocks/database/PrivateDatabase.kt
+9
-3
mobile/src/main/java/com/github/shadowsocks/database/Profile.kt
.../src/main/java/com/github/shadowsocks/database/Profile.kt
+21
-20
mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt
...in/java/com/github/shadowsocks/database/ProfileManager.kt
+14
-8
mobile/src/main/java/com/github/shadowsocks/database/PublicDatabase.kt
...in/java/com/github/shadowsocks/database/PublicDatabase.kt
+50
-0
mobile/src/main/java/com/github/shadowsocks/plugin/PluginManager.kt
.../main/java/com/github/shadowsocks/plugin/PluginManager.kt
+1
-1
mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt
.../main/java/com/github/shadowsocks/preference/DataStore.kt
+43
-86
mobile/src/main/java/com/github/shadowsocks/preference/OrmLitePreferenceDataStore.kt
...thub/shadowsocks/preference/OrmLitePreferenceDataStore.kt
+82
-0
mobile/src/main/java/com/github/shadowsocks/utils/Constants.kt
...e/src/main/java/com/github/shadowsocks/utils/Constants.kt
+6
-1
mobile/src/main/java/com/github/shadowsocks/utils/DeviceContext.kt
...c/main/java/com/github/shadowsocks/utils/DeviceContext.kt
+34
-0
mobile/src/main/java/com/github/shadowsocks/utils/DirectBoot.kt
.../src/main/java/com/github/shadowsocks/utils/DirectBoot.kt
+31
-0
mobile/src/main/java/com/github/shadowsocks/utils/TcpFastOpen.kt
...src/main/java/com/github/shadowsocks/utils/TcpFastOpen.kt
+1
-0
mobile/src/main/res/values/strings.xml
mobile/src/main/res/values/strings.xml
+3
-0
mobile/src/main/res/xml/backup_descriptor.xml
mobile/src/main/res/xml/backup_descriptor.xml
+6
-1
mobile/src/main/res/xml/pref_global.xml
mobile/src/main/res/xml/pref_global.xml
+5
-0
No files found.
mobile/src/main/AndroidManifest.xml
View file @
612a34a6
...
...
@@ -113,6 +113,7 @@
<service
android:name=
".bg.VpnService"
android:process=
":bg"
android:directBootAware=
"true"
android:label=
"@string/app_name"
android:permission=
"android.permission.BIND_VPN_SERVICE"
android:exported=
"false"
>
...
...
@@ -124,17 +125,20 @@
<service
android:name=
".bg.TransproxyService"
android:process=
":bg"
android:directBootAware=
"true"
android:exported=
"false"
>
</service>
<service
android:name=
".bg.ProxyService"
android:process=
":bg"
android:directBootAware=
"true"
android:exported=
"false"
>
</service>
<service
android:name=
".bg.TileService"
android:label=
"@string/quick_toggle"
android:process=
":bg"
android:directBootAware=
"true"
android:icon=
"@drawable/ic_start_connected"
android:permission=
"android.permission.BIND_QUICK_SETTINGS_TILE"
>
<intent-filter>
...
...
@@ -142,13 +146,20 @@
</intent-filter>
</service>
<receiver
android:name=
".BootReceiver"
android:process=
":bg"
android:enabled=
"false"
>
<receiver
android:name=
".BootReceiver"
android:process=
":bg"
android:directBootAware=
"true"
android:enabled=
"false"
>
<intent-filter>
<action
android:name=
"android.intent.action.BOOT_COMPLETED"
/>
<action
android:name=
"android.intent.action.LOCKED_BOOT_COMPLETED"
/>
</intent-filter>
</receiver>
<receiver
android:name=
".tasker.ActionListener"
android:process=
":bg"
tools:ignore=
"ExportedReceiver"
>
<receiver
android:name=
".tasker.ActionListener"
android:process=
":bg"
android:directBootAware=
"true"
tools:ignore=
"ExportedReceiver"
>
<intent-filter>
<action
android:name=
"com.twofortyfouram.locale.intent.action.FIRE_SETTING"
/>
</intent-filter>
...
...
@@ -156,16 +167,22 @@
<!-- android-job components -->
<service
android:name=
"com.evernote.android.job.v21.PlatformJobService"
android:process=
":bg"
/>
android:process=
":bg"
android:directBootAware=
"true"
/>
<service
android:name=
"com.evernote.android.job.v14.PlatformAlarmService"
android:process=
":bg"
/>
android:process=
":bg"
android:directBootAware=
"true"
/>
<service
android:name=
"com.evernote.android.job.gcm.PlatformGcmService"
android:process=
":bg"
/>
android:process=
":bg"
android:directBootAware=
"true"
/>
<service
android:name=
"com.evernote.android.job.JobRescheduleService"
android:process=
":bg"
/>
android:process=
":bg"
android:directBootAware=
"true"
/>
<receiver
android:name=
"com.evernote.android.job.v14.PlatformAlarmReceiver"
android:process=
":bg"
/>
android:process=
":bg"
android:directBootAware=
"true"
/>
<receiver
android:name=
"com.evernote.android.job.JobBootReceiver"
android:process=
":bg"
/>
android:process=
":bg"
android:directBootAware=
"true"
/>
</application>
</manifest>
mobile/src/main/java/com/evernote/android/job/JobConstants.kt
0 → 100644
View file @
612a34a6
/*******************************************************************************
* *
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package
com.evernote.android.job
object
JobConstants
{
const
val
DATABASE_NAME
=
JobStorage
.
DATABASE_NAME
const
val
PREF_FILE_NAME
=
JobStorage
.
PREF_FILE_NAME
}
mobile/src/main/java/com/github/shadowsocks/App.kt
View file @
612a34a6
...
...
@@ -24,6 +24,7 @@ import android.app.Application
import
android.app.NotificationChannel
import
android.app.NotificationManager
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
android.content.IntentFilter
import
android.content.pm.PackageInfo
...
...
@@ -34,9 +35,12 @@ import android.os.Handler
import
android.os.LocaleList
import
android.os.Looper
import
android.support.annotation.RequiresApi
import
android.support.v4.os.UserManagerCompat
import
android.support.v7.app.AppCompatDelegate
import
android.util.Log
import
com.evernote.android.job.JobConstants
import
com.evernote.android.job.JobManager
import
com.github.shadowsocks.acl.Acl
import
com.github.shadowsocks.acl.AclSyncJob
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.database.Profile
...
...
@@ -44,10 +48,7 @@ import com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.preference.BottomSheetPreferenceDialogFragment
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.IconListPreference
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.TcpFastOpen
import
com.github.shadowsocks.utils.broadcastReceiver
import
com.github.shadowsocks.utils.*
import
com.google.android.gms.analytics.GoogleAnalytics
import
com.google.android.gms.analytics.HitBuilders
import
com.google.android.gms.analytics.StandardExceptionParser
...
...
@@ -75,8 +76,9 @@ class App : Application() {
}
val
handler
by
lazy
{
Handler
(
Looper
.
getMainLooper
())
}
val
deviceContext
:
Context
by
lazy
{
if
(
Build
.
VERSION
.
SDK_INT
<
24
)
this
else
DeviceContext
(
this
)
}
val
remoteConfig
:
FirebaseRemoteConfig
by
lazy
{
FirebaseRemoteConfig
.
getInstance
()
}
private
val
tracker
:
Tracker
by
lazy
{
GoogleAnalytics
.
getInstance
(
this
).
newTracker
(
R
.
xml
.
tracker
)
}
private
val
tracker
:
Tracker
by
lazy
{
GoogleAnalytics
.
getInstance
(
deviceContext
).
newTracker
(
R
.
xml
.
tracker
)
}
val
info
:
PackageInfo
by
lazy
{
packageManager
.
getPackageInfo
(
packageName
,
PackageManager
.
GET_SIGNATURES
)
}
fun
startService
()
{
...
...
@@ -86,7 +88,8 @@ class App : Application() {
fun
reloadService
()
=
sendBroadcast
(
Intent
(
Action
.
RELOAD
))
fun
stopService
()
=
sendBroadcast
(
Intent
(
Action
.
CLOSE
))
val
currentProfile
:
Profile
?
get
()
=
ProfileManager
.
getProfile
(
DataStore
.
profileId
)
val
currentProfile
:
Profile
?
get
()
=
if
(
DataStore
.
directBootAware
)
DirectBoot
.
getDeviceProfile
()
else
ProfileManager
.
getProfile
(
DataStore
.
profileId
)
fun
switchProfile
(
id
:
Int
):
Profile
{
val
result
=
ProfileManager
.
getProfile
(
id
)
?:
ProfileManager
.
createProfile
()
...
...
@@ -162,31 +165,42 @@ class App : Application() {
if
(!
BuildConfig
.
DEBUG
)
System
.
setProperty
(
LocalLog
.
LOCAL_LOG_LEVEL_PROPERTY
,
"ERROR"
)
AppCompatDelegate
.
setCompatVectorFromResourcesEnabled
(
true
)
checkChineseLocale
(
resources
.
configuration
)
PreferenceFragmentCompat
.
registerPreferenceFragment
(
IconListPreference
::
class
.
java
,
BottomSheetPreferenceDialogFragment
::
class
.
java
)
if
(
Build
.
VERSION
.
SDK_INT
>=
24
)
{
// migrate old files
deviceContext
.
moveDatabaseFrom
(
this
,
Key
.
DB_PUBLIC
)
deviceContext
.
moveDatabaseFrom
(
this
,
JobConstants
.
DATABASE_NAME
)
deviceContext
.
moveSharedPreferencesFrom
(
this
,
JobConstants
.
PREF_FILE_NAME
)
val
old
=
Acl
.
getFile
(
Acl
.
CUSTOM_RULES
,
this
)
if
(
old
.
canRead
())
{
Acl
.
getFile
(
Acl
.
CUSTOM_RULES
).
writeText
(
old
.
readText
())
old
.
delete
()
}
}
FirebaseApp
.
initializeApp
(
this
)
FirebaseApp
.
initializeApp
(
deviceContext
)
remoteConfig
.
setDefaults
(
R
.
xml
.
default_configs
)
remoteConfig
.
fetch
().
addOnCompleteListener
{
if
(
it
.
isSuccessful
)
remoteConfig
.
activateFetched
()
else
Log
.
e
(
TAG
,
"Failed to fetch config"
)
}
JobManager
.
create
(
deviceContext
).
addJobCreator
(
AclSyncJob
)
JobManager
.
create
(
this
).
addJobCreator
(
AclSyncJob
)
PreferenceFragmentCompat
.
registerPreferenceFragment
(
IconListPreference
::
class
.
java
,
BottomSheetPreferenceDialogFragment
::
class
.
java
)
TcpFastOpen
.
enabled
(
DataStore
.
getBoolean
(
Key
.
tfo
,
TcpFastOpen
.
sendEnabled
))
if
(
DataStore
.
getLong
(
Key
.
assetUpdateTime
,
-
1
)
!=
info
.
lastUpdateTime
)
{
// handle data restored
if
(
DataStore
.
directBootAware
&&
UserManagerCompat
.
isUserUnlocked
(
this
))
DirectBoot
.
update
()
TcpFastOpen
.
enabled
(
DataStore
.
publicStore
.
getBoolean
(
Key
.
tfo
,
TcpFastOpen
.
sendEnabled
))
if
(
DataStore
.
publicStore
.
getLong
(
Key
.
assetUpdateTime
,
-
1
)
!=
info
.
lastUpdateTime
)
{
val
assetManager
=
assets
for
(
dir
in
arrayOf
(
"acl"
,
"overture"
))
try
{
for
(
file
in
assetManager
.
list
(
dir
))
assetManager
.
open
(
dir
+
'/'
+
file
).
use
{
input
->
File
(
filesDir
,
file
).
outputStream
().
use
{
output
->
input
.
copyTo
(
output
)
}
File
(
deviceContext
.
filesDir
,
file
).
outputStream
().
use
{
output
->
input
.
copyTo
(
output
)
}
}
}
catch
(
e
:
IOException
)
{
Log
.
e
(
TAG
,
e
.
message
)
app
.
track
(
e
)
}
DataStore
.
putLong
(
Key
.
assetUpdateTime
,
info
.
lastUpdateTime
)
DataStore
.
pu
blicStore
.
pu
tLong
(
Key
.
assetUpdateTime
,
info
.
lastUpdateTime
)
}
if
(
Build
.
VERSION
.
SDK_INT
>=
26
)
@RequiresApi
(
26
)
{
...
...
mobile/src/main/java/com/github/shadowsocks/AppManager.kt
View file @
612a34a6
...
...
@@ -47,6 +47,7 @@ import com.futuremind.recyclerviewfastscroll.SectionTitleProvider
import
com.github.shadowsocks.App.Companion.app
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.thread
import
java.util.concurrent.atomic.AtomicBoolean
...
...
@@ -231,6 +232,7 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
it
.
individual
=
proxiedAppString
ProfileManager
.
updateProfile
(
it
)
}
if
(
DataStore
.
directBootAware
)
DirectBoot
.
update
()
Toast
.
makeText
(
this
,
R
.
string
.
action_apply_all
,
Toast
.
LENGTH_SHORT
).
show
()
}
else
Toast
.
makeText
(
this
,
R
.
string
.
action_export_err
,
Toast
.
LENGTH_SHORT
).
show
()
return
true
...
...
mobile/src/main/java/com/github/shadowsocks/BootReceiver.kt
View file @
612a34a6
...
...
@@ -26,6 +26,7 @@ import android.content.Context
import
android.content.Intent
import
android.content.pm.PackageManager
import
com.github.shadowsocks.App.Companion.app
import
com.github.shadowsocks.preference.DataStore
class
BootReceiver
:
BroadcastReceiver
()
{
companion
object
{
...
...
@@ -39,6 +40,11 @@ class BootReceiver : BroadcastReceiver() {
}
override
fun
onReceive
(
context
:
Context
,
intent
:
Intent
)
{
if
(
intent
.
action
==
Intent
.
ACTION_BOOT_COMPLETED
)
app
.
startService
()
val
locked
=
when
(
intent
.
action
)
{
Intent
.
ACTION_BOOT_COMPLETED
->
false
Intent
.
ACTION_LOCKED_BOOT_COMPLETED
->
true
// constant will be folded so no need to do version checks
else
->
return
}
if
(
DataStore
.
directBootAware
==
locked
)
app
.
startService
()
}
}
mobile/src/main/java/com/github/shadowsocks/ConfigBackupHelper.kt
View file @
612a34a6
...
...
@@ -27,6 +27,6 @@ import com.github.shadowsocks.utils.Key
@Deprecated
(
"Only used in API level < 23. For 6.0+, Auto Backup for Apps is used."
)
class
ConfigBackupHelper
:
BackupAgentHelper
()
{
override
fun
onCreate
()
=
addHelper
(
"com.github.shadowsocks.database.profile"
,
FileBackupHelper
(
this
,
"../databases/"
+
Key
.
PROFILE
,
Acl
.
CUSTOM_RULES
+
".acl"
))
override
fun
onCreate
()
=
addHelper
(
"com.github.shadowsocks.database.profile"
,
FileBackupHelper
(
this
,
"../databases/"
+
Key
.
DB_PROFILE
,
"../databases/"
+
Key
.
DB_PUBLIC
,
Acl
.
CUSTOM_RULES
+
".acl"
))
}
mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
View file @
612a34a6
...
...
@@ -20,27 +20,40 @@
package
com.github.shadowsocks
import
android.app.admin.DevicePolicyManager
import
android.os.Build
import
android.os.Bundle
import
android.support.design.widget.Snackbar
import
android.support.v14.preference.SwitchPreference
import
android.support.v7.preference.Preference
import
com.github.shadowsocks.App.Companion.app
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.TcpFastOpen
import
com.takisoft.fix.support.v7.preference.PreferenceFragmentCompatDividers
class
GlobalSettingsPreferenceFragment
:
PreferenceFragmentCompatDividers
()
{
override
fun
onCreatePreferencesFix
(
savedInstanceState
:
Bundle
?,
rootKey
:
String
?)
{
preferenceManager
.
preferenceDataStore
=
DataStore
preferenceManager
.
preferenceDataStore
=
DataStore
.
publicStore
DataStore
.
initGlobal
()
addPreferencesFromResource
(
R
.
xml
.
pref_global
)
val
switch
=
findPreference
(
Key
.
isAutoConnect
)
as
SwitchPreference
switch
.
setOnPreferenceChangeListener
{
_
,
v
alue
->
BootReceiver
.
enabled
=
value
as
Boolean
val
boot
=
findPreference
(
Key
.
isAutoConnect
)
as
SwitchPreference
val
directBootAwareListener
=
Preference
.
OnPreferenceChangeListener
{
_
,
newV
alue
->
if
(
newValue
as
Boolean
)
DirectBoot
.
update
()
else
DirectBoot
.
clean
()
true
}
switch
.
isChecked
=
BootReceiver
.
enabled
boot
.
setOnPreferenceChangeListener
{
_
,
value
->
BootReceiver
.
enabled
=
value
as
Boolean
directBootAwareListener
.
onPreferenceChange
(
null
,
DataStore
.
directBootAware
)
}
boot
.
isChecked
=
BootReceiver
.
enabled
val
dba
=
findPreference
(
Key
.
directBootAware
)
if
(
Build
.
VERSION
.
SDK_INT
>=
24
&&
context
!!
.
getSystemService
(
DevicePolicyManager
::
class
.
java
)
.
storageEncryptionStatus
==
DevicePolicyManager
.
ENCRYPTION_STATUS_ACTIVE_PER_USER
)
dba
.
onPreferenceChangeListener
=
directBootAwareListener
else
dba
.
parent
!!
.
removePreference
(
dba
)
val
tfo
=
findPreference
(
Key
.
tfo
)
as
SwitchPreference
tfo
.
isChecked
=
TcpFastOpen
.
sendEnabled
...
...
mobile/src/main/java/com/github/shadowsocks/MainActivity.kt
View file @
612a34a6
...
...
@@ -335,7 +335,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
changeState
(
BaseService
.
IDLE
)
// reset everything to init state
app
.
handler
.
post
{
connection
.
connect
()
}
DataStore
.
registerChangeListener
(
this
)
DataStore
.
publicStore
.
registerChangeListener
(
this
)
val
intent
=
this
.
intent
if
(
intent
!=
null
)
handleShareIntent
(
intent
)
...
...
@@ -434,7 +434,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
override
fun
onDestroy
()
{
super
.
onDestroy
()
DataStore
.
unregisterChangeListener
(
this
)
DataStore
.
publicStore
.
unregisterChangeListener
(
this
)
connection
.
disconnect
()
BackupManager
(
this
).
dataChanged
()
app
.
handler
.
removeCallbacksAndMessages
(
null
)
...
...
mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt
View file @
612a34a6
...
...
@@ -45,6 +45,7 @@ import com.github.shadowsocks.preference.IconListPreference
import
com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import
com.github.shadowsocks.preference.PluginConfigurationDialogFragment
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.Key
import
com.takisoft.fix.support.v7.preference.EditTextPreference
import
com.takisoft.fix.support.v7.preference.PreferenceFragmentCompatDividers
...
...
@@ -62,7 +63,7 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
private
lateinit
var
pluginConfiguration
:
PluginConfiguration
override
fun
onCreatePreferencesFix
(
savedInstanceState
:
Bundle
?,
rootKey
:
String
?)
{
preferenceManager
.
preferenceDataStore
=
DataStore
preferenceManager
.
preferenceDataStore
=
DataStore
.
privateStore
val
activity
=
activity
!!
val
profile
=
ProfileManager
.
getProfile
(
activity
.
intent
.
getIntExtra
(
Action
.
EXTRA_PROFILE_ID
,
-
1
))
if
(
profile
==
null
)
{
...
...
@@ -102,7 +103,7 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
pluginConfigure
.
onPreferenceChangeListener
=
this
initPlugins
()
app
.
listenForPackageChanges
{
initPlugins
()
}
DataStore
.
registerChangeListener
(
this
)
DataStore
.
privateStore
.
registerChangeListener
(
this
)
}
private
fun
initPlugins
()
{
...
...
@@ -130,6 +131,7 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
profile
.
deserialize
()
ProfileManager
.
updateProfile
(
profile
)
ProfilesFragment
.
instance
?.
profilesAdapter
?.
deepRefreshId
(
profile
.
id
)
if
(
DataStore
.
profileId
==
profile
.
id
&&
DataStore
.
directBootAware
)
DirectBoot
.
update
()
activity
!!
.
finish
()
}
...
...
@@ -201,7 +203,7 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
}
override
fun
onDestroy
()
{
DataStore
.
unregisterChangeListener
(
this
)
DataStore
.
privateStore
.
unregisterChangeListener
(
this
)
super
.
onDestroy
()
}
}
mobile/src/main/java/com/github/shadowsocks/acl/Acl.kt
View file @
612a34a6
...
...
@@ -20,6 +20,7 @@
package
com.github.shadowsocks.acl
import
android.content.Context
import
android.support.v7.util.SortedList
import
android.util.Log
import
com.github.shadowsocks.App.Companion.app
...
...
@@ -45,7 +46,7 @@ class Acl {
val
networkAclParser
=
"^IMPORT_URL\\s*<(.+)>\\s*$"
.
toRegex
()
fun
getFile
(
id
:
String
)
=
File
(
app
.
filesDir
,
id
+
".acl"
)
fun
getFile
(
id
:
String
,
context
:
Context
=
app
.
deviceContext
)
=
File
(
context
.
filesDir
,
id
+
".acl"
)
val
customRules
:
Acl
get
()
{
val
acl
=
Acl
()
...
...
@@ -56,7 +57,7 @@ class Acl {
acl
.
bypassHostnames
.
clear
()
// everything is bypassed
return
acl
}
fun
save
(
id
:
String
,
acl
:
Acl
)
:
Unit
=
getFile
(
id
).
bufferedWriter
().
use
{
it
.
write
(
acl
.
toString
())
}
fun
save
(
id
:
String
,
acl
:
Acl
)
=
getFile
(
id
).
writeText
(
acl
.
toString
())
}
private
abstract
class
BaseSorter
<
T
>
:
SortedList
.
Callback
<
T
>()
{
...
...
mobile/src/main/java/com/github/shadowsocks/bg/BaseService.kt
View file @
612a34a6
...
...
@@ -20,11 +20,15 @@
package
com.github.shadowsocks.bg
import
android.annotation.TargetApi
import
android.app.Service
import
android.content.Context
import
android.content.Intent
import
android.content.IntentFilter
import
android.os.*
import
android.os.Build
import
android.os.IBinder
import
android.os.RemoteCallbackList
import
android.support.v4.os.UserManagerCompat
import
android.text.TextUtils
import
android.util.Base64
import
android.util.Log
...
...
@@ -66,6 +70,8 @@ object BaseService {
const
val
STOPPING
=
3
const
val
STOPPED
=
4
const
val
CONFIG_FILE
=
"shadowsocks.conf"
class
Data
internal
constructor
(
private
val
service
:
Interface
)
{
@Volatile
var
profile
:
Profile
?
=
null
@Volatile
var
state
=
STOPPED
...
...
@@ -163,7 +169,8 @@ object BaseService {
}
}
internal
fun
buildShadowsocksConfig
()
{
internal
var
shadowsocksConfigFile
:
File
?
=
null
internal
fun
buildShadowsocksConfig
():
File
{
val
profile
=
profile
!!
val
config
=
JSONObject
()
.
put
(
"server"
,
profile
.
host
)
...
...
@@ -178,7 +185,13 @@ object BaseService {
.
put
(
"plugin"
,
Commandline
.
toString
(
service
.
buildAdditionalArguments
(
pluginCmd
)))
.
put
(
"plugin_opts"
,
plugin
.
toString
())
}
File
(
app
.
filesDir
,
"shadowsocks.json"
).
bufferedWriter
().
use
{
it
.
write
(
config
.
toString
())
}
// sensitive Shadowsocks config is stored in
val
file
=
File
((
if
(
UserManagerCompat
.
isUserUnlocked
(
app
))
app
.
filesDir
else
@TargetApi
(
24
)
{
app
.
deviceContext
.
noBackupFilesDir
// only API 24+ will be in locked state
}),
CONFIG_FILE
)
shadowsocksConfigFile
=
file
file
.
writeText
(
config
.
toString
())
return
file
}
val
aclFile
:
File
?
get
()
{
...
...
@@ -228,14 +241,13 @@ object BaseService {
fun
startNativeProcesses
()
{
val
data
=
data
data
.
buildShadowsocksConfig
()
val
cmd
=
buildAdditionalArguments
(
arrayListOf
(
File
((
this
as
Context
).
applicationInfo
.
nativeLibraryDir
,
Executable
.
SS_LOCAL
).
absolutePath
,
"-u"
,
"-b"
,
"127.0.0.1"
,
"-l"
,
DataStore
.
portProxy
.
toString
(),
"-t"
,
"600"
,
"-c"
,
"shadowsocks.json"
))
"-c"
,
data
.
buildShadowsocksConfig
().
absolutePath
))
val
acl
=
data
.
aclFile
if
(
acl
!=
null
)
{
...
...
@@ -278,6 +290,9 @@ object BaseService {
data
.
closeReceiverRegistered
=
false
}
data
.
shadowsocksConfigFile
?.
delete
()
// remove old config possibly in device storage
data
.
shadowsocksConfigFile
=
null
data
.
notification
?.
destroy
()
data
.
notification
=
null
...
...
mobile/src/main/java/com/github/shadowsocks/bg/Executable.kt
View file @
612a34a6
...
...
@@ -37,8 +37,7 @@ object Executable {
fun
killAll
()
{
for
(
process
in
File
(
"/proc"
).
listFiles
{
_
,
name
->
TextUtils
.
isDigitsOnly
(
name
)
})
{
val
exe
=
File
(
File
(
process
,
"cmdline"
).
bufferedReader
().
use
{
it
.
readText
()
}
.
split
(
Character
.
MIN_VALUE
,
limit
=
2
).
first
())
val
exe
=
File
(
File
(
process
,
"cmdline"
).
readText
().
split
(
Character
.
MIN_VALUE
,
limit
=
2
).
first
())
if
(
exe
.
parent
==
app
.
applicationInfo
.
nativeLibraryDir
&&
EXECUTABLES
.
contains
(
exe
.
name
))
{
val
errno
=
JniHelper
.
sigkill
(
process
.
name
.
toInt
())
if
(
errno
!=
0
)
Log
.
w
(
"kill"
,
"SIGKILL ${exe.absolutePath} (${process.name}) failed with $errno"
)
...
...
mobile/src/main/java/com/github/shadowsocks/bg/GuardedProcess.kt
View file @
612a34a6
...
...
@@ -62,7 +62,7 @@ class GuardedProcess(private val cmd: List<String>) {
process
=
ProcessBuilder
(
cmd
)
.
redirectErrorStream
(
true
)
.
directory
(
app
.
filesDir
)
.
directory
(
app
.
deviceContext
.
filesDir
)
.
start
()
streamLogger
(
process
.
inputStream
,
Log
::
i
)
...
...
mobile/src/main/java/com/github/shadowsocks/bg/LocalDnsService.kt
View file @
612a34a6
...
...
@@ -99,7 +99,7 @@ object LocalDnsService {
// no need to setup AlternativeDNS in Acl.ALL/BYPASS_LAN mode
.
put
(
"OnlyPrimaryDNS"
,
true
)
}
File
(
filesDir
,
file
).
bufferedWriter
().
use
{
it
.
write
(
config
.
toString
())
}
File
(
app
.
deviceContext
.
filesDir
,
file
).
writeText
(
config
.
toString
())
return
file
}
...
...
mobile/src/main/java/com/github/shadowsocks/bg/TrafficMonitorThread.kt
View file @
612a34a6
...
...
@@ -29,7 +29,7 @@ import java.nio.ByteBuffer
import
java.nio.ByteOrder
class
TrafficMonitorThread
:
LocalSocketListener
(
"TrafficMonitorThread"
)
{
override
val
socketFile
=
File
(
app
.
filesDir
,
"/
stat_path"
)
override
val
socketFile
=
File
(
app
.
deviceContext
.
filesDir
,
"
stat_path"
)
override
fun
accept
(
socket
:
LocalSocket
)
{
try
{
...
...
mobile/src/main/java/com/github/shadowsocks/bg/TransproxyService.kt
View file @
612a34a6
...
...
@@ -23,6 +23,7 @@ package com.github.shadowsocks.bg
import
android.app.Service
import
android.content.Intent
import
android.os.IBinder
import
com.github.shadowsocks.App.Companion.app
import
com.github.shadowsocks.preference.DataStore
import
java.io.File
...
...
@@ -49,12 +50,12 @@ class TransproxyService : Service(), LocalDnsService.Interface {
"-u"
,
"-l"
,
DataStore
.
portLocalDns
.
toString
(),
// ss-tunnel listens on the same port as overture
"-L"
,
data
.
profile
!!
.
remoteDns
.
split
(
","
).
first
().
trim
()
+
":53"
,
"-c"
,
"shadowsocks.json"
)
// config is already built by BaseService.Interface
"-c"
,
data
.
shadowsocksConfigFile
!!
.
absolutePath
)
// config is already built by BaseService.Interface
sstunnelProcess
=
GuardedProcess
(
cmd
).
start
()
}
private
fun
startRedsocksDaemon
()
{
val
config
=
"""base {
File
(
app
.
deviceContext
.
filesDir
,
"redsocks.conf"
).
writeText
(
"""base {
log_debug = off;
log_info = off;
log = stderr;
...
...
@@ -68,8 +69,7 @@ redsocks {
port = ${DataStore.portProxy};
type = socks5;
}
"""
File
(
filesDir
,
"redsocks.conf"
).
bufferedWriter
().
use
{
it
.
write
(
config
)
}
"""
)
redsocksProcess
=
GuardedProcess
(
arrayListOf
(
File
(
applicationInfo
.
nativeLibraryDir
,
Executable
.
REDSOCKS
).
absolutePath
,
"-c"
,
"redsocks.conf"
)
...
...
mobile/src/main/java/com/github/shadowsocks/bg/VpnService.kt
View file @
612a34a6
...
...
@@ -52,7 +52,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
}
private
inner
class
ProtectWorker
:
LocalSocketListener
(
"ShadowsocksVpnThread"
)
{
override
val
socketFile
:
File
=
File
(
filesDir
,
"protect_path"
)
override
val
socketFile
:
File
=
File
(
app
.
deviceContext
.
filesDir
,
"protect_path"
)
override
fun
accept
(
socket
:
LocalSocket
)
{
try
{
...
...
@@ -197,7 +197,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
var
tries
=
1
while
(
tries
<
5
)
{
Thread
.
sleep
(
1000L
*
tries
)
if
(
JniHelper
.
sendFd
(
fd
,
File
(
filesDir
,
"sock_path"
).
absolutePath
)
!=
-
1
)
return
true
if
(
JniHelper
.
sendFd
(
fd
,
File
(
app
.
deviceContext
.
filesDir
,
"sock_path"
).
absolutePath
)
!=
-
1
)
return
true
tries
+=
1
}
}
...
...
mobile/src/main/java/com/github/shadowsocks/database/
DBHelper
.kt
→
mobile/src/main/java/com/github/shadowsocks/database/
PrivateDatabase
.kt
View file @
612a34a6
...
...
@@ -31,7 +31,7 @@ import com.j256.ormlite.dao.Dao
import
com.j256.ormlite.support.ConnectionSource
import
com.j256.ormlite.table.TableUtils
object
DBHelper
:
OrmLiteSqliteOpenHelper
(
app
,
Key
.
PROFILE
,
null
,
24
)
{
object
PrivateDatabase
:
OrmLiteSqliteOpenHelper
(
app
,
Key
.
DB_PROFILE
,
null
,
25
)
{
@Suppress
(
"UNCHECKED_CAST"
)
val
profileDao
:
Dao
<
Profile
,
Int
>
by
lazy
{
getDao
(
Profile
::
class
.
java
)
as
Dao
<
Profile
,
Int
>
}
@Suppress
(
"UNCHECKED_CAST"
)
...
...
@@ -134,8 +134,14 @@ object DBHelper : OrmLiteSqliteOpenHelper(app, Key.PROFILE, null, 24) {
TableUtils
.
createTable
(
connectionSource
,
KeyValuePair
::
class
.
java
)
profileDao
.
executeRawNoArgs
(
"COMMIT;"
)
val
old
=
PreferenceManager
.
getDefaultSharedPreferences
(
app
)
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
Key
.
id
).
put
(
old
.
getInt
(
Key
.
id
,
0
)))
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
Key
.
tfo
).
put
(
old
.
getBoolean
(
Key
.
tfo
,
false
)))
PublicDatabase
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
Key
.
id
).
put
(
old
.
getInt
(
Key
.
id
,
0
)))
PublicDatabase
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
Key
.
tfo
).
put
(
old
.
getBoolean
(
Key
.
tfo
,
false
)))
}
if
(
oldVersion
<
25
)
{
kvPairDao
.
queryBuilder
().
where
().
`in`
(
"key"
,
Key
.
id
,
Key
.
tfo
,
Key
.
serviceMode
,
Key
.
portProxy
,
Key
.
portLocalDns
,
Key
.
portTransproxy
).
query
()
.
forEach
{
PublicDatabase
.
kvPairDao
.
createOrUpdate
(
it
)
}
}
}
catch
(
ex
:
Exception
)
{
app
.
track
(
ex
)
...
...
mobile/src/main/java/com/github/shadowsocks/database/Profile.kt
View file @
612a34a6
...
...
@@ -29,10 +29,11 @@ import com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.parsePort
import
com.j256.ormlite.field.DataType
import
com.j256.ormlite.field.DatabaseField
import
java.io.Serializable
import
java.net.URI
import
java.util.*
class
Profile
{
class
Profile
:
Serializable
{
companion
object
{
private
const
val
TAG
=
"ShadowParser"
private
val
pattern
=
"""(?i)ss://[-a-zA-Z0-9+&@#/%?=~_|!:,.;\[\]]*[-a-zA-Z0-9+&@#/%=~_|\[\]]"""
.
toRegex
()
...
...
@@ -153,34 +154,34 @@ class Profile {
override
fun
toString
()
=
toUri
().
toString
()
fun
serialize
()
{
DataStore
.
putString
(
Key
.
name
,
name
)
DataStore
.
putString
(
Key
.
host
,
host
)
DataStore
.
putString
(
Key
.
remotePort
,
remotePort
.
toString
())
DataStore
.
putString
(
Key
.
password
,
password
)
DataStore
.
putString
(
Key
.
route
,
route
)
DataStore
.
putString
(
Key
.
remoteDns
,
remoteDns
)
DataStore
.
putString
(
Key
.
method
,
method
)
DataStore
.
p
rivateStore
.
p
utString
(
Key
.
name
,
name
)
DataStore
.
p
rivateStore
.
p
utString
(
Key
.
host
,
host
)
DataStore
.
p
rivateStore
.
p
utString
(
Key
.
remotePort
,
remotePort
.
toString
())
DataStore
.
p
rivateStore
.
p
utString
(
Key
.
password
,
password
)
DataStore
.
p
rivateStore
.
p
utString
(
Key
.
route
,
route
)
DataStore
.
p
rivateStore
.
p
utString
(
Key
.
remoteDns
,
remoteDns
)
DataStore
.
p
rivateStore
.
p
utString
(
Key
.
method
,
method
)
DataStore
.
proxyApps
=
proxyApps
DataStore
.
bypass
=
bypass
DataStore
.
putBoolean
(
Key
.
udpdns
,
udpdns
)
DataStore
.
putBoolean
(
Key
.
ipv6
,
ipv6
)
DataStore
.
p
rivateStore
.
p
utBoolean
(
Key
.
udpdns
,
udpdns
)
DataStore
.
p
rivateStore
.
p
utBoolean
(
Key
.
ipv6
,
ipv6
)
DataStore
.
individual
=
individual
DataStore
.
plugin
=
plugin
?:
""
DataStore
.
remove
(
Key
.
dirty
)
DataStore
.
privateStore
.
remove
(
Key
.
dirty
)
}
fun
deserialize
()
{
// It's assumed that default values are never used, so 0/false/null is always used even if that isn't the case
name
=
DataStore
.
getString
(
Key
.
name
)
?:
""
host
=
DataStore
.
getString
(
Key
.
host
)
?:
""
remotePort
=
parsePort
(
DataStore
.
getString
(
Key
.
remotePort
),
8388
,
1
)
password
=
DataStore
.
getString
(
Key
.
password
)
?:
""
method
=
DataStore
.
getString
(
Key
.
method
)
?:
""
route
=
DataStore
.
getString
(
Key
.
route
)
?:
""
remoteDns
=
DataStore
.
getString
(
Key
.
remoteDns
)
?:
""
name
=
DataStore
.
privateStore
.
getString
(
Key
.
name
)
?:
""
host
=
DataStore
.
privateStore
.
getString
(
Key
.
host
)
?:
""
remotePort
=
parsePort
(
DataStore
.
privateStore
.
getString
(
Key
.
remotePort
),
8388
,
1
)
password
=
DataStore
.
privateStore
.
getString
(
Key
.
password
)
?:
""
method
=
DataStore
.
privateStore
.
getString
(
Key
.
method
)
?:
""
route
=
DataStore
.
privateStore
.
getString
(
Key
.
route
)
?:
""
remoteDns
=
DataStore
.
privateStore
.
getString
(
Key
.
remoteDns
)
?:
""
proxyApps
=
DataStore
.
proxyApps
bypass
=
DataStore
.
bypass
udpdns
=
DataStore
.
getBoolean
(
Key
.
udpdns
,
false
)
ipv6
=
DataStore
.
getBoolean
(
Key
.
ipv6
,
false
)
udpdns
=
DataStore
.
privateStore
.
getBoolean
(
Key
.
udpdns
,
false
)
ipv6
=
DataStore
.
privateStore
.
getBoolean
(
Key
.
ipv6
,
false
)
individual
=
DataStore
.
individual
plugin
=
DataStore
.
plugin
}
...
...
mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt
View file @
612a34a6
...
...
@@ -23,6 +23,8 @@ package com.github.shadowsocks.database
import
android.util.Log
import
com.github.shadowsocks.App.Companion.app
import
com.github.shadowsocks.ProfilesFragment
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.DirectBoot
object
ProfileManager
{
private
const
val
TAG
=
"ProfileManager"
...
...
@@ -41,10 +43,10 @@ object ProfileManager {
profile
.
individual
=
oldProfile
.
individual
profile
.
udpdns
=
oldProfile
.
udpdns
}
val
last
=
DBHelper
.
profileDao
.
queryRaw
(
DBHelper
.
profileDao
.
queryBuilder
().
selectRaw
(
"MAX(userOrder)"
)
.
prepareStatementString
()).
firstResult
val
last
=
PrivateDatabase
.
profileDao
.
queryRaw
(
PrivateDatabase
.
profileDao
.
queryBuilder
(
)
.
selectRaw
(
"MAX(userOrder)"
).
prepareStatementString
()).
firstResult
if
(
last
!=
null
&&
last
.
size
==
1
&&
last
[
0
]
!=
null
)
profile
.
userOrder
=
last
[
0
].
toLong
()
+
1
DBHelper
.
profileDao
.
createOrUpdate
(
profile
)
PrivateDatabase
.
profileDao
.
createOrUpdate
(
profile
)
ProfilesFragment
.
instance
?.
profilesAdapter
?.
add
(
profile
)
}
catch
(
ex
:
Exception
)
{
Log
.
e
(
TAG
,
"addProfile"
,
ex
)
...
...
@@ -53,8 +55,11 @@ object ProfileManager {
return
profile
}
/**
* Note: It's caller's responsibility to update DirectBoot profile if necessary.
*/
fun
updateProfile
(
profile
:
Profile
):
Boolean
=
try
{
DBHelper
.
profileDao
.
update
(
profile
)
PrivateDatabase
.
profileDao
.
update
(
profile
)
true
}
catch
(
ex
:
Exception
)
{
Log
.
e
(
TAG
,
"updateProfile"
,
ex
)
...
...
@@ -63,7 +68,7 @@ object ProfileManager {
}
fun
getProfile
(
id
:
Int
):
Profile
?
=
try
{
DBHelper
.
profileDao
.
queryForId
(
id
)
PrivateDatabase
.
profileDao
.
queryForId
(
id
)
}
catch
(
ex
:
Exception
)
{
Log
.
e
(
TAG
,
"getProfile"
,
ex
)
app
.
track
(
ex
)
...
...
@@ -71,8 +76,9 @@ object ProfileManager {
}
fun
delProfile
(
id
:
Int
):
Boolean
=
try
{
DBHelper
.
profileDao
.
deleteById
(
id
)
PrivateDatabase
.
profileDao
.
deleteById
(
id
)
ProfilesFragment
.
instance
?.
profilesAdapter
?.
removeId
(
id
)
if
(
id
==
DataStore
.
profileId
&&
DataStore
.
directBootAware
)
DirectBoot
.
clean
()
true
}
catch
(
ex
:
Exception
)
{
Log
.
e
(
TAG
,
"delProfile"
,
ex
)
...
...
@@ -81,7 +87,7 @@ object ProfileManager {
}
fun
getFirstProfile
():
Profile
?
=
try
{
val
result
=
DBHelper
.
profileDao
.
query
(
DBHelper
.
profileDao
.
queryBuilder
().
limit
(
1L
).
prepare
())
val
result
=
PrivateDatabase
.
profileDao
.
query
(
PrivateDatabase
.
profileDao
.
queryBuilder
().
limit
(
1L
).
prepare
())
if
(
result
.
size
==
1
)
result
[
0
]
else
null
}
catch
(
ex
:
Exception
)
{
Log
.
e
(
TAG
,
"getAllProfiles"
,
ex
)
...
...
@@ -90,7 +96,7 @@ object ProfileManager {
}
fun
getAllProfiles
():
List
<
Profile
>?
=
try
{
DBHelper
.
profileDao
.
query
(
DBHelper
.
profileDao
.
queryBuilder
().
orderBy
(
"userOrder"
,
true
).
prepare
())
PrivateDatabase
.
profileDao
.
query
(
PrivateDatabase
.
profileDao
.
queryBuilder
().
orderBy
(
"userOrder"
,
true
).
prepare
())
}
catch
(
ex
:
Exception
)
{
Log
.
e
(
TAG
,
"getAllProfiles"
,
ex
)
app
.
track
(
ex
)
...
...
mobile/src/main/java/com/github/shadowsocks/database/PublicDatabase.kt
0 → 100644
View file @
612a34a6
/*******************************************************************************
* *
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package
com.github.shadowsocks.database
import
android.database.sqlite.SQLiteDatabase
import
com.github.shadowsocks.App.Companion.app
import
com.github.shadowsocks.utils.Key
import
com.j256.ormlite.android.AndroidDatabaseConnection
import
com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper
import
com.j256.ormlite.dao.Dao
import
com.j256.ormlite.support.ConnectionSource
import
com.j256.ormlite.table.TableUtils
object
PublicDatabase
:
OrmLiteSqliteOpenHelper
(
app
.
deviceContext
,
Key
.
DB_PUBLIC
,
null
,
1
)
{
@Suppress
(
"UNCHECKED_CAST"
)
val
kvPairDao
:
Dao
<
KeyValuePair
,
String
?
>
by
lazy
{
getDao
(
KeyValuePair
::
class
.
java
)
as
Dao
<
KeyValuePair
,
String
?
>
}
override
fun
onCreate
(
database
:
SQLiteDatabase
?,
connectionSource
:
ConnectionSource
?)
{
TableUtils
.
createTable
(
connectionSource
,
KeyValuePair
::
class
.
java
)
}
override
fun
onUpgrade
(
database
:
SQLiteDatabase
?,
connectionSource
:
ConnectionSource
?,
oldVersion
:
Int
,
newVersion
:
Int
)
{
}
override
fun
onDowngrade
(
db
:
SQLiteDatabase
?,
oldVersion
:
Int
,
newVersion
:
Int
)
{
val
connection
=
AndroidDatabaseConnection
(
db
,
true
)
connectionSource
.
saveSpecialConnection
(
connection
)
TableUtils
.
dropTable
<
KeyValuePair
,
String
?>(
connectionSource
,
KeyValuePair
::
class
.
java
,
true
)
onCreate
(
db
,
connectionSource
)
connectionSource
.
clearSpecialConnection
(
connection
)
}
}
mobile/src/main/java/com/github/shadowsocks/plugin/PluginManager.kt
View file @
612a34a6
...
...
@@ -157,7 +157,7 @@ object PluginManager {
var
initialized
=
false
fun
entryNotFound
():
Nothing
=
throw
IndexOutOfBoundsException
(
"Plugin entry binary not found"
)
val
list
=
ArrayList
<
String
>()
val
pluginDir
=
File
(
app
.
filesDir
,
"plugin"
)
val
pluginDir
=
File
(
app
.
deviceContext
.
filesDir
,
"plugin"
)
(
cr
.
query
(
uri
,
arrayOf
(
PluginContract
.
COLUMN_PATH
,
PluginContract
.
COLUMN_MODE
),
null
,
null
,
null
)
?:
return
null
).
use
{
cursor
->
if
(!
cursor
.
moveToFirst
())
entryNotFound
()
...
...
mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt
View file @
612a34a6
...
...
@@ -21,115 +21,72 @@
package
com.github.shadowsocks.preference
import
android.os.Binder
import
android.support.v7.preference.PreferenceDataStore
import
com.github.shadowsocks.database.DBHelper
import
com.github.shadowsocks.database.KeyValuePair
import
com.github.shadowsocks.BootReceiver
import
com.github.shadowsocks.database.PrivateDatabase
import
com.github.shadowsocks.database.PublicDatabase
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.parsePort
import
java.util.*
@Suppress
(
"MemberVisibilityCanPrivate"
,
"unused"
)
object
DataStore
:
PreferenceDataStore
()
{
fun
getBoolean
(
key
:
String
?)
=
DBHelper
.
kvPairDao
.
queryForId
(
key
)
?.
boolean
fun
getFloat
(
key
:
String
?)
=
DBHelper
.
kvPairDao
.
queryForId
(
key
)
?.
float
fun
getInt
(
key
:
String
?)
=
DBHelper
.
kvPairDao
.
queryForId
(
key
)
?.
int
fun
getLong
(
key
:
String
?)
=
DBHelper
.
kvPairDao
.
queryForId
(
key
)
?.
long
fun
getString
(
key
:
String
?)
=
DBHelper
.
kvPairDao
.
queryForId
(
key
)
?.
string
fun
getStringSet
(
key
:
String
?)
=
DBHelper
.
kvPairDao
.
queryForId
(
key
)
?.
stringSet
override
fun
getBoolean
(
key
:
String
?,
defValue
:
Boolean
)
=
getBoolean
(
key
)
?:
defValue
override
fun
getFloat
(
key
:
String
?,
defValue
:
Float
)
=
getFloat
(
key
)
?:
defValue
override
fun
getInt
(
key
:
String
?,
defValue
:
Int
)
=
getInt
(
key
)
?:
defValue
override
fun
getLong
(
key
:
String
?,
defValue
:
Long
)
=
getLong
(
key
)
?:
defValue
override
fun
getString
(
key
:
String
?,
defValue
:
String
?)
=
getString
(
key
)
?:
defValue
override
fun
getStringSet
(
key
:
String
?,
defValue
:
MutableSet
<
String
>?)
=
getStringSet
(
key
)
?:
defValue
fun
putBoolean
(
key
:
String
?,
value
:
Boolean
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putBoolean
(
key
,
value
)
fun
putFloat
(
key
:
String
?,
value
:
Float
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putFloat
(
key
,
value
)
fun
putInt
(
key
:
String
?,
value
:
Int
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putInt
(
key
,
value
)
fun
putLong
(
key
:
String
?,
value
:
Long
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putLong
(
key
,
value
)
override
fun
putBoolean
(
key
:
String
?,
value
:
Boolean
)
{
DBHelper
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putFloat
(
key
:
String
?,
value
:
Float
)
{
DBHelper
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putInt
(
key
:
String
?,
value
:
Int
)
{
DBHelper
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putLong
(
key
:
String
?,
value
:
Long
)
{
DBHelper
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putString
(
key
:
String
?,
value
:
String
?)
=
if
(
value
==
null
)
remove
(
key
)
else
{
DBHelper
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putStringSet
(
key
:
String
?,
values
:
MutableSet
<
String
>?)
=
if
(
values
==
null
)
remove
(
key
)
else
{
DBHelper
.
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
values
))
fireChangeListener
(
key
)
}
fun
remove
(
key
:
String
?)
{
DBHelper
.
kvPairDao
.
deleteById
(
key
)
fireChangeListener
(
key
)
}
private
val
listeners
=
HashSet
<
OnPreferenceDataStoreChangeListener
>()
private
fun
fireChangeListener
(
key
:
String
?)
=
listeners
.
forEach
{
it
.
onPreferenceDataStoreChanged
(
this
,
key
)
}
fun
registerChangeListener
(
listener
:
OnPreferenceDataStoreChangeListener
)
=
listeners
.
add
(
listener
)
fun
unregisterChangeListener
(
listener
:
OnPreferenceDataStoreChangeListener
)
=
listeners
.
remove
(
listener
)
object
DataStore
{
val
publicStore
=
OrmLitePreferenceDataStore
(
PublicDatabase
.
kvPairDao
)
// privateStore will only be used as temp storage for ProfileConfigFragment
val
privateStore
=
OrmLitePreferenceDataStore
(
PrivateDatabase
.
kvPairDao
)
// hopefully hashCode = mHandle doesn't change, currently this is true from KitKat to Nougat
private
val
userIndex
by
lazy
{
Binder
.
getCallingUserHandle
().
hashCode
()
}
private
fun
getLocalPort
(
key
:
String
,
default
:
Int
):
Int
{
val
value
=
getInt
(
key
)
val
value
=
publicStore
.
getInt
(
key
)
return
if
(
value
!=
null
)
{
putString
(
key
,
value
.
toString
())
pu
blicStore
.
pu
tString
(
key
,
value
.
toString
())
value
}
else
parsePort
(
getString
(
key
),
default
+
userIndex
)
}
else
parsePort
(
publicStore
.
getString
(
key
),
default
+
userIndex
)
}
var
profileId
:
Int
get
()
=
getInt
(
Key
.
id
)
?:
0
set
(
value
)
=
putInt
(
Key
.
id
,
value
)
get
()
=
publicStore
.
getInt
(
Key
.
id
)
?:
0
set
(
value
)
{
publicStore
.
putInt
(
Key
.
id
,
value
)
if
(
DataStore
.
directBootAware
)
DirectBoot
.
update
()
}
/**
* Setter is defined in MainActivity.onPreferenceDataStoreChanged.
*/
val
directBootAware
:
Boolean
get
()
=
BootReceiver
.
enabled
&&
(
publicStore
.
getBoolean
(
Key
.
directBootAware
)
?:
false
)
var
serviceMode
:
String
get
()
=
getString
(
Key
.
serviceMode
)
?:
Key
.
modeVpn
set
(
value
)
=
putString
(
Key
.
serviceMode
,
value
)
get
()
=
publicStore
.
getString
(
Key
.
serviceMode
)
?:
Key
.
modeVpn
set
(
value
)
=
pu
blicStore
.
pu
tString
(
Key
.
serviceMode
,
value
)
var
portProxy
:
Int
get
()
=
getLocalPort
(
Key
.
portProxy
,
1080
)
set
(
value
)
=
putString
(
Key
.
portProxy
,
value
.
toString
())
set
(
value
)
=
pu
blicStore
.
pu
tString
(
Key
.
portProxy
,
value
.
toString
())
var
portLocalDns
:
Int
get
()
=
getLocalPort
(
Key
.
portLocalDns
,
5450
)
set
(
value
)
=
putString
(
Key
.
portLocalDns
,
value
.
toString
())
set
(
value
)
=
pu
blicStore
.
pu
tString
(
Key
.
portLocalDns
,
value
.
toString
())
var
portTransproxy
:
Int
get
()
=
getLocalPort
(
Key
.
portTransproxy
,
8200
)
set
(
value
)
=
putString
(
Key
.
portTransproxy
,
value
.
toString
())
set
(
value
)
=
publicStore
.
putString
(
Key
.
portTransproxy
,
value
.
toString
())
fun
initGlobal
()
{
// temporary workaround for support lib bug
if
(
publicStore
.
getString
(
Key
.
serviceMode
)
==
null
)
serviceMode
=
serviceMode
if
(
publicStore
.
getString
(
Key
.
portProxy
)
==
null
)
portProxy
=
portProxy
if
(
publicStore
.
getString
(
Key
.
portLocalDns
)
==
null
)
portLocalDns
=
portLocalDns
if
(
publicStore
.
getString
(
Key
.
portTransproxy
)
==
null
)
portTransproxy
=
portTransproxy
}
var
proxyApps
:
Boolean
get
()
=
getBoolean
(
Key
.
proxyApps
)
?:
false
set
(
value
)
=
putBoolean
(
Key
.
proxyApps
,
value
)
get
()
=
privateStore
.
getBoolean
(
Key
.
proxyApps
)
?:
false
set
(
value
)
=
p
rivateStore
.
p
utBoolean
(
Key
.
proxyApps
,
value
)
var
bypass
:
Boolean
get
()
=
getBoolean
(
Key
.
bypass
)
?:
false
set
(
value
)
=
putBoolean
(
Key
.
bypass
,
value
)
get
()
=
privateStore
.
getBoolean
(
Key
.
bypass
)
?:
false
set
(
value
)
=
p
rivateStore
.
p
utBoolean
(
Key
.
bypass
,
value
)
var
individual
:
String
get
()
=
getString
(
Key
.
individual
)
?:
""
set
(
value
)
=
putString
(
Key
.
individual
,
value
)
get
()
=
privateStore
.
getString
(
Key
.
individual
)
?:
""
set
(
value
)
=
p
rivateStore
.
p
utString
(
Key
.
individual
,
value
)
var
plugin
:
String
get
()
=
getString
(
Key
.
plugin
)
?:
""
set
(
value
)
=
putString
(
Key
.
plugin
,
value
)
get
()
=
privateStore
.
getString
(
Key
.
plugin
)
?:
""
set
(
value
)
=
p
rivateStore
.
p
utString
(
Key
.
plugin
,
value
)
var
dirty
:
Boolean
get
()
=
getBoolean
(
Key
.
dirty
)
?:
false
set
(
value
)
=
putBoolean
(
Key
.
dirty
,
value
)
fun
initGlobal
()
{
// temporary workaround for support lib bug
if
(
getString
(
Key
.
serviceMode
)
==
null
)
serviceMode
=
serviceMode
if
(
getString
(
Key
.
portProxy
)
==
null
)
portProxy
=
portProxy
if
(
getString
(
Key
.
portLocalDns
)
==
null
)
portLocalDns
=
portLocalDns
if
(
getString
(
Key
.
portTransproxy
)
==
null
)
portTransproxy
=
portTransproxy
}
get
()
=
privateStore
.
getBoolean
(
Key
.
dirty
)
?:
false
set
(
value
)
=
privateStore
.
putBoolean
(
Key
.
dirty
,
value
)
}
mobile/src/main/java/com/github/shadowsocks/preference/OrmLitePreferenceDataStore.kt
0 → 100644
View file @
612a34a6
/*******************************************************************************
* *
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package
com.github.shadowsocks.preference
import
android.support.v7.preference.PreferenceDataStore
import
com.github.shadowsocks.database.KeyValuePair
import
com.j256.ormlite.dao.Dao
import
java.util.HashSet
@Suppress
(
"MemberVisibilityCanPrivate"
,
"unused"
)
open
class
OrmLitePreferenceDataStore
(
private
val
kvPairDao
:
Dao
<
KeyValuePair
,
String
?
>)
:
PreferenceDataStore
()
{
fun
getBoolean
(
key
:
String
?)
=
kvPairDao
.
queryForId
(
key
)
?.
boolean
fun
getFloat
(
key
:
String
?)
=
kvPairDao
.
queryForId
(
key
)
?.
float
fun
getInt
(
key
:
String
?)
=
kvPairDao
.
queryForId
(
key
)
?.
int
fun
getLong
(
key
:
String
?)
=
kvPairDao
.
queryForId
(
key
)
?.
long
fun
getString
(
key
:
String
?)
=
kvPairDao
.
queryForId
(
key
)
?.
string
fun
getStringSet
(
key
:
String
?)
=
kvPairDao
.
queryForId
(
key
)
?.
stringSet
override
fun
getBoolean
(
key
:
String
?,
defValue
:
Boolean
)
=
getBoolean
(
key
)
?:
defValue
override
fun
getFloat
(
key
:
String
?,
defValue
:
Float
)
=
getFloat
(
key
)
?:
defValue
override
fun
getInt
(
key
:
String
?,
defValue
:
Int
)
=
getInt
(
key
)
?:
defValue
override
fun
getLong
(
key
:
String
?,
defValue
:
Long
)
=
getLong
(
key
)
?:
defValue
override
fun
getString
(
key
:
String
?,
defValue
:
String
?)
=
getString
(
key
)
?:
defValue
override
fun
getStringSet
(
key
:
String
?,
defValue
:
MutableSet
<
String
>?)
=
getStringSet
(
key
)
?:
defValue
fun
putBoolean
(
key
:
String
?,
value
:
Boolean
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putBoolean
(
key
,
value
)
fun
putFloat
(
key
:
String
?,
value
:
Float
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putFloat
(
key
,
value
)
fun
putInt
(
key
:
String
?,
value
:
Int
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putInt
(
key
,
value
)
fun
putLong
(
key
:
String
?,
value
:
Long
?)
=
if
(
value
==
null
)
remove
(
key
)
else
putLong
(
key
,
value
)
override
fun
putBoolean
(
key
:
String
?,
value
:
Boolean
)
{
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putFloat
(
key
:
String
?,
value
:
Float
)
{
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putInt
(
key
:
String
?,
value
:
Int
)
{
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putLong
(
key
:
String
?,
value
:
Long
)
{
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putString
(
key
:
String
?,
value
:
String
?)
=
if
(
value
==
null
)
remove
(
key
)
else
{
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
value
))
fireChangeListener
(
key
)
}
override
fun
putStringSet
(
key
:
String
?,
values
:
MutableSet
<
String
>?)
=
if
(
values
==
null
)
remove
(
key
)
else
{
kvPairDao
.
createOrUpdate
(
KeyValuePair
(
key
).
put
(
values
))
fireChangeListener
(
key
)
}
fun
remove
(
key
:
String
?)
{
kvPairDao
.
deleteById
(
key
)
fireChangeListener
(
key
)
}
private
val
listeners
=
HashSet
<
OnPreferenceDataStoreChangeListener
>()
private
fun
fireChangeListener
(
key
:
String
?)
=
listeners
.
forEach
{
it
.
onPreferenceDataStoreChanged
(
this
,
key
)
}
fun
registerChangeListener
(
listener
:
OnPreferenceDataStoreChangeListener
)
=
listeners
.
add
(
listener
)
fun
unregisterChangeListener
(
listener
:
OnPreferenceDataStoreChangeListener
)
=
listeners
.
remove
(
listener
)
}
mobile/src/main/java/com/github/shadowsocks/utils/Constants.kt
View file @
612a34a6
...
...
@@ -21,7 +21,11 @@
package
com.github.shadowsocks.utils
object
Key
{
const
val
PROFILE
=
"profile.db"
/**
* Public config that doesn't need to be kept secret.
*/
const
val
DB_PUBLIC
=
"config.db"
const
val
DB_PROFILE
=
"profile.db"
const
val
id
=
"profileId"
const
val
name
=
"profileName"
...
...
@@ -39,6 +43,7 @@ object Key {
const
val
route
=
"route"
const
val
isAutoConnect
=
"isAutoConnect"
const
val
directBootAware
=
"directBootAware"
const
val
proxyApps
=
"isProxyApps"
const
val
bypass
=
"isBypassApps"
...
...
mobile/src/main/java/com/github/shadowsocks/utils/DeviceContext.kt
0 → 100644
View file @
612a34a6
/*******************************************************************************
* *
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package
com.github.shadowsocks.utils
import
android.annotation.TargetApi
import
android.content.Context
import
android.content.ContextWrapper
@TargetApi
(
24
)
class
DeviceContext
(
context
:
Context
)
:
ContextWrapper
(
context
.
createDeviceProtectedStorageContext
())
{
/**
* Thou shalt not get the REAL underlying application context which would no longer be operating under device
* protected storage.
*/
override
fun
getApplicationContext
():
Context
=
this
}
mobile/src/main/java/com/github/shadowsocks/utils/DirectBoot.kt
0 → 100644
View file @
612a34a6
package
com.github.shadowsocks.utils
import
android.annotation.TargetApi
import
com.github.shadowsocks.App.Companion.app
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.preference.DataStore
import
java.io.File
import
java.io.FileNotFoundException
import
java.io.ObjectInputStream
import
java.io.ObjectOutputStream
@TargetApi
(
24
)
object
DirectBoot
{
private
val
file
=
File
(
app
.
deviceContext
.
noBackupFilesDir
,
"directBootProfile"
)
fun
getDeviceProfile
():
Profile
?
=
try
{
ObjectInputStream
(
file
.
inputStream
()).
use
{
it
.
readObject
()
as
Profile
}
}
catch
(
_
:
FileNotFoundException
)
{
null
}
fun
clean
()
{
file
.
delete
()
File
(
app
.
deviceContext
.
noBackupFilesDir
,
BaseService
.
CONFIG_FILE
).
delete
()
}
fun
update
()
{
val
profile
=
ProfileManager
.
getProfile
(
DataStore
.
profileId
)
// app.currentProfile will call this
if
(
profile
==
null
)
clean
()
else
ObjectOutputStream
(
file
.
outputStream
()).
use
{
it
.
writeObject
(
profile
)
}
}
}
mobile/src/main/java/com/github/shadowsocks/utils/TcpFastOpen.kt
View file @
612a34a6
...
...
@@ -42,6 +42,7 @@ object TcpFastOpen {
val
sendEnabled
:
Boolean
get
()
{
val
file
=
File
(
"/proc/sys/net/ipv4/tcp_fastopen"
)
// File.readText doesn't work since this special file will return length 0
return
file
.
canRead
()
&&
file
.
bufferedReader
().
use
{
it
.
readText
()
}.
trim
().
toInt
()
and
1
>
0
}
...
...
mobile/src/main/res/values/strings.xml
View file @
612a34a6
...
...
@@ -57,6 +57,9 @@
<string
name=
"auto_connect_summary"
>
Enable Shadowsocks on startup
</string>
<string
name=
"auto_connect_summary_v24"
>
Enable Shadowsocks on startup. Recommended to use always-on VPN
instead
</string>
<string
name=
"direct_boot_aware"
>
Direct Boot Aware
</string>
<string
name=
"direct_boot_aware_summary"
>
Allow Shadowsocks to start before your device is unlocked (your selected
profile information will be less protected)
</string>
<string
name=
"tcp_fastopen_summary"
>
Toggling requires ROOT permission
</string>
<string
name=
"tcp_fastopen_summary_unsupported"
>
Unsupported kernel version: %s
<
3.7.1
</string>
<string
name=
"udp_dns"
>
DNS Forwarding
</string>
...
...
mobile/src/main/res/xml/backup_descriptor.xml
View file @
612a34a6
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<full-backup-content
xmlns:tools=
"http://schemas.android.com/tools"
tools:ignore=
"FullBackupContent"
>
<include
domain=
"database"
path=
"profile.db"
/>
<!-- No device storage yet in Android 6.0 -->
<include
domain=
"database"
path=
"config.db"
/>
<include
domain=
"file"
path=
"custom-rules.acl"
/>
<include
domain=
"device_database"
path=
"config.db"
/>
<include
domain=
"device_file"
path=
"custom-rules.acl"
/>
</full-backup-content>
mobile/src/main/res/xml/pref_global.xml
View file @
612a34a6
...
...
@@ -5,6 +5,11 @@
android:persistent=
"false"
android:summary=
"@string/auto_connect_summary"
android:title=
"@string/auto_connect"
/>
<!-- Direct Boot Aware alone doesn't do anything without auto connect -->
<SwitchPreference
android:key=
"directBootAware"
android:dependency=
"isAutoConnect"
android:summary=
"@string/direct_boot_aware_summary"
android:title=
"@string/direct_boot_aware"
/>
<SwitchPreference
android:key=
"tcp_fastopen"
android:summary=
"@string/tcp_fastopen_summary"
android:title=
"TCP Fast Open"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment