Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
4a48f59d
Commit
4a48f59d
authored
Aug 20, 2016
by
dvdandroid
Committed by
topjohnwu
Aug 22, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Changed root method
parent
bc2c63bf
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
2287 additions
and
201 deletions
+2287
-201
gradle.xml
.idea/gradle.xml
+4
-0
misc.xml
.idea/misc.xml
+0
-41
modules.xml
.idea/modules.xml
+2
-0
build.gradle
app/build.gradle
+1
-0
ApplicationTest.java
...ndroidTest/java/com/topjohnwu/magisk/ApplicationTest.java
+0
-13
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+2
-2
Module.java
app/src/main/java/com/topjohnwu/magisk/model/Module.java
+1
-1
ModulesAdapter.java
...src/main/java/com/topjohnwu/magisk/rv/ModulesAdapter.java
+60
-0
MainActivity.java
app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.java
+16
-73
ModulesActivity.java
...rc/main/java/com/topjohnwu/magisk/ui/ModulesActivity.java
+5
-53
Utils.java
app/src/main/java/com/topjohnwu/magisk/ui/utils/Utils.java
+28
-0
activity_main.xml
app/src/main/res/layout/activity_main.xml
+1
-1
activity_modules.xml
app/src/main/res/layout/activity_modules.xml
+1
-1
ExampleUnitTest.java
app/src/test/java/com/topjohnwu/magisk/ExampleUnitTest.java
+0
-15
.gitignore
lib/RootCommands/.gitignore
+2
-0
build.gradle
lib/RootCommands/build.gradle
+20
-0
AndroidManifest.xml
lib/RootCommands/src/main/AndroidManifest.xml
+6
-0
Mount.java
.../main/java/org/sufficientlysecure/rootcommands/Mount.java
+58
-0
Remounter.java
...n/java/org/sufficientlysecure/rootcommands/Remounter.java
+188
-0
RootCommands.java
...ava/org/sufficientlysecure/rootcommands/RootCommands.java
+49
-0
Shell.java
.../main/java/org/sufficientlysecure/rootcommands/Shell.java
+347
-0
SystemCommands.java
...a/org/sufficientlysecure/rootcommands/SystemCommands.java
+120
-0
Toolbox.java
...ain/java/org/sufficientlysecure/rootcommands/Toolbox.java
+772
-0
Command.java
.../org/sufficientlysecure/rootcommands/command/Command.java
+169
-0
ExecutableCommand.java
...cientlysecure/rootcommands/command/ExecutableCommand.java
+65
-0
SimpleCommand.java
...ufficientlysecure/rootcommands/command/SimpleCommand.java
+43
-0
SimpleExecutableCommand.java
...ysecure/rootcommands/command/SimpleExecutableCommand.java
+45
-0
BrokenBusyboxException.java
...entlysecure/rootcommands/util/BrokenBusyboxException.java
+32
-0
Log.java
...in/java/org/sufficientlysecure/rootcommands/util/Log.java
+82
-0
RootAccessDeniedException.java
...lysecure/rootcommands/util/RootAccessDeniedException.java
+32
-0
UnsupportedArchitectureException.java
...e/rootcommands/util/UnsupportedArchitectureException.java
+30
-0
Utils.java
.../java/org/sufficientlysecure/rootcommands/util/Utils.java
+105
-0
settings.gradle
settings.gradle
+1
-1
No files found.
.idea/gradle.xml
View file @
4a48f59d
...
@@ -10,12 +10,16 @@
...
@@ -10,12 +10,16 @@
<set>
<set>
<option
value=
"$PROJECT_DIR$"
/>
<option
value=
"$PROJECT_DIR$"
/>
<option
value=
"$PROJECT_DIR$/app"
/>
<option
value=
"$PROJECT_DIR$/app"
/>
<option
value=
"$PROJECT_DIR$/lib"
/>
<option
value=
"$PROJECT_DIR$/lib/RootCommands"
/>
</set>
</set>
</option>
</option>
<option
name=
"myModules"
>
<option
name=
"myModules"
>
<set>
<set>
<option
value=
"$PROJECT_DIR$"
/>
<option
value=
"$PROJECT_DIR$"
/>
<option
value=
"$PROJECT_DIR$/app"
/>
<option
value=
"$PROJECT_DIR$/app"
/>
<option
value=
"$PROJECT_DIR$/lib"
/>
<option
value=
"$PROJECT_DIR$/lib/RootCommands"
/>
</set>
</set>
</option>
</option>
</GradleProjectSettings>
</GradleProjectSettings>
...
...
.idea/misc.xml
View file @
4a48f59d
...
@@ -27,47 +27,6 @@
...
@@ -27,47 +27,6 @@
</value>
</value>
</option>
</option>
</component>
</component>
<component
name=
"ProjectInspectionProfilesVisibleTreeState"
>
<entry
key=
"Project Default"
>
<profile-state>
<expanded-state>
<State>
<id>
Android Lint
</id>
</State>
<State>
<id>
Groovy
</id>
</State>
<State>
<id>
HTML
</id>
</State>
<State>
<id>
J2ME issues
</id>
</State>
<State>
<id>
JUnit issues
</id>
</State>
<State>
<id>
Java language level issues
</id>
</State>
<State>
<id>
JavaBeans issues
</id>
</State>
<State>
<id>
Pattern Validation
</id>
</State>
<State>
<id>
Threading issues
</id>
</State>
<State>
<id>
Threading issuesGroovy
</id>
</State>
<State>
<id>
XML
</id>
</State>
</expanded-state>
</profile-state>
</entry>
</component>
<component
name=
"ProjectLevelVcsManager"
settingsEditedManually=
"false"
>
<component
name=
"ProjectLevelVcsManager"
settingsEditedManually=
"false"
>
<OptionsSetting
value=
"true"
id=
"Add"
/>
<OptionsSetting
value=
"true"
id=
"Add"
/>
<OptionsSetting
value=
"true"
id=
"Remove"
/>
<OptionsSetting
value=
"true"
id=
"Remove"
/>
...
...
.idea/modules.xml
View file @
4a48f59d
...
@@ -3,7 +3,9 @@
...
@@ -3,7 +3,9 @@
<component
name=
"ProjectModuleManager"
>
<component
name=
"ProjectModuleManager"
>
<modules>
<modules>
<module
fileurl=
"file://$PROJECT_DIR$/MagiskManager.iml"
filepath=
"$PROJECT_DIR$/MagiskManager.iml"
/>
<module
fileurl=
"file://$PROJECT_DIR$/MagiskManager.iml"
filepath=
"$PROJECT_DIR$/MagiskManager.iml"
/>
<module
fileurl=
"file://$PROJECT_DIR$/lib/RootCommands/RootCommands.iml"
filepath=
"$PROJECT_DIR$/lib/RootCommands/RootCommands.iml"
/>
<module
fileurl=
"file://$PROJECT_DIR$/app/app.iml"
filepath=
"$PROJECT_DIR$/app/app.iml"
/>
<module
fileurl=
"file://$PROJECT_DIR$/app/app.iml"
filepath=
"$PROJECT_DIR$/app/app.iml"
/>
<module
fileurl=
"file://$PROJECT_DIR$/lib/lib.iml"
filepath=
"$PROJECT_DIR$/lib/lib.iml"
/>
</modules>
</modules>
</component>
</component>
</project>
</project>
\ No newline at end of file
app/build.gradle
View file @
4a48f59d
...
@@ -25,4 +25,5 @@ android {
...
@@ -25,4 +25,5 @@ android {
dependencies
{
dependencies
{
compile
fileTree
(
dir:
'libs'
,
include:
[
'*.jar'
])
compile
fileTree
(
dir:
'libs'
,
include:
[
'*.jar'
])
compile
project
(
':lib:RootCommands'
)
}
}
app/src/androidTest/java/com/topjohnwu/magisk/ApplicationTest.java
deleted
100644 → 0
View file @
bc2c63bf
package
com
.
topjohnwu
.
magisk
;
import
android.app.Application
;
import
android.test.ApplicationTestCase
;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public
class
ApplicationTest
extends
ApplicationTestCase
<
Application
>
{
public
ApplicationTest
()
{
super
(
Application
.
class
);
}
}
\ No newline at end of file
app/src/main/AndroidManifest.xml
View file @
4a48f59d
...
@@ -8,14 +8,14 @@
...
@@ -8,14 +8,14 @@
android:label=
"@string/app_name"
android:label=
"@string/app_name"
android:supportsRtl=
"true"
android:supportsRtl=
"true"
android:theme=
"@style/AppTheme"
>
android:theme=
"@style/AppTheme"
>
<activity
android:name=
".MainActivity"
>
<activity
android:name=
".
ui.
MainActivity"
>
<intent-filter>
<intent-filter>
<action
android:name=
"android.intent.action.MAIN"
/>
<action
android:name=
"android.intent.action.MAIN"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</intent-filter>
</activity>
</activity>
<activity
android:name=
".ModulesActivity"
>
<activity
android:name=
".
ui.
ModulesActivity"
>
</activity>
</activity>
</application>
</application>
...
...
app/src/main/java/com/topjohnwu/magisk/Module.java
→
app/src/main/java/com/topjohnwu/magisk/
model/
Module.java
View file @
4a48f59d
package
com
.
topjohnwu
.
magisk
;
package
com
.
topjohnwu
.
magisk
.
model
;
import
java.io.BufferedReader
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.File
;
...
...
app/src/main/java/com/topjohnwu/magisk/rv/ModulesAdapter.java
0 → 100644
View file @
4a48f59d
package
com
.
topjohnwu
.
magisk
.
rv
;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.ArrayAdapter
;
import
android.widget.TextView
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.model.Module
;
import
java.util.List
;
public
class
ModulesAdapter
extends
ArrayAdapter
<
Module
>
{
public
ModulesAdapter
(
Context
context
,
int
resource
,
List
<
Module
>
modules
)
{
super
(
context
,
resource
,
modules
);
}
@SuppressLint
(
"SetTextI18n"
)
@Override
public
View
getView
(
int
position
,
View
convertView
,
ViewGroup
parent
)
{
ViewHolder
vh
;
if
(
convertView
==
null
)
{
LayoutInflater
inflater
=
(
LayoutInflater
)
getContext
().
getSystemService
(
Context
.
LAYOUT_INFLATER_SERVICE
);
convertView
=
inflater
.
inflate
(
R
.
layout
.
row
,
null
);
vh
=
new
ViewHolder
();
vh
.
name
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
name
);
vh
.
version
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
version
);
vh
.
versionCode
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
versionCode
);
vh
.
description
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
description
);
vh
.
cache
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
cache
);
convertView
.
setTag
(
vh
);
}
else
{
vh
=
(
ViewHolder
)
convertView
.
getTag
();
}
Module
module
=
getItem
(
position
);
vh
.
name
.
setText
(
"name= "
+
module
.
getName
());
vh
.
version
.
setText
(
"version= "
+
module
.
getVersion
());
vh
.
versionCode
.
setText
(
"versioncode= "
+
module
.
getVersionCode
());
vh
.
description
.
setText
(
"description= "
+
module
.
getDescription
());
vh
.
cache
.
setText
(
"is from cache= "
+
module
.
isCache
());
return
convertView
;
}
static
class
ViewHolder
{
public
TextView
name
;
public
TextView
version
;
public
TextView
versionCode
;
public
TextView
description
;
public
TextView
cache
;
}
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/MainActivity.java
→
app/src/main/java/com/topjohnwu/magisk/
ui/
MainActivity.java
View file @
4a48f59d
package
com
.
topjohnwu
.
magisk
;
package
com
.
topjohnwu
.
magisk
.
ui
;
import
android.app.Activity
;
import
android.app.Activity
;
import
android.content.Intent
;
import
android.content.Intent
;
import
android.graphics.Color
;
import
android.graphics.Color
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
import
android.os.Bundle
;
import
android.os.Handler
;
import
android.widget.Switch
;
import
android.widget.Switch
;
import
android.widget.TextView
;
import
android.widget.TextView
;
import
java.io.BufferedReader
;
import
com.topjohnwu.magisk.R
;
import
java.io.DataOutputStream
;
import
java.io.File
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
static
com
.
topjohnwu
.
magisk
.
ui
.
utils
.
Utils
.
executeCommand
;
public
class
MainActivity
extends
Activity
{
public
class
MainActivity
extends
Activity
{
...
@@ -34,59 +32,29 @@ public class MainActivity extends Activity {
...
@@ -34,59 +32,29 @@ public class MainActivity extends Activity {
safetyNet
=
(
TextView
)
findViewById
(
R
.
id
.
safety_net
);
safetyNet
=
(
TextView
)
findViewById
(
R
.
id
.
safety_net
);
permissive
=
(
TextView
)
findViewById
(
R
.
id
.
permissive
);
permissive
=
(
TextView
)
findViewById
(
R
.
id
.
permissive
);
suPath
=
execute
(
"getprop magisk.supath"
);
suPath
=
execute
Command
(
"getprop magisk.supath"
);
updateStatus
();
updateStatus
();
rootToggle
.
setOnClickListener
(
view
->
{
rootToggle
.
setOnCheckedChangeListener
((
view
,
checked
)
->
{
Switch
s
=
(
Switch
)
view
;
executeCommand
(
checked
?
"setprop magisk.root 1"
:
"setprop magisk.root 0"
);
if
(
s
.
isChecked
())
{
updateStatus
();
(
new
SU
()).
execute
(
"setprop magisk.root 1"
);
}
else
{
(
new
SU
()).
execute
(
"setprop magisk.root 0"
);
}
});
});
selinuxToggle
.
setOnClickListener
(
view
->
{
selinuxToggle
.
setOnCheckedChangeListener
((
view
,
checked
)
->
{
Switch
s
=
(
Switch
)
view
;
executeCommand
(
checked
?
"setenforce 1"
:
"setenforce 0"
);
if
(
s
.
isChecked
())
{
updateStatus
();
new
SU
().
execute
(
"setenforce 1"
);
}
else
{
new
SU
().
execute
(
"setenforce 0"
);
}
});
});
findViewById
(
R
.
id
.
modules
).
setOnClickListener
(
view
->
startActivity
(
new
Intent
(
this
,
ModulesActivity
.
class
)));
findViewById
(
R
.
id
.
modules
).
setOnClickListener
(
view
->
startActivity
(
new
Intent
(
this
,
ModulesActivity
.
class
)));
}
}
private
String
execute
(
String
command
)
{
StringBuilder
output
=
new
StringBuilder
();
Process
p
;
try
{
p
=
Runtime
.
getRuntime
().
exec
(
command
);
p
.
waitFor
();
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
p
.
getInputStream
()));
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
if
(
output
.
length
()
!=
0
)
output
.
append
(
"\n"
);
output
.
append
(
line
);
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
output
.
toString
();
}
private
void
updateStatus
()
{
private
void
updateStatus
()
{
String
selinux
=
executeCommand
(
"getenforce"
);
String
selinux
=
execute
(
"getenforce"
);
magiskVersion
.
setText
(
getString
(
R
.
string
.
magisk_version
,
executeCommand
(
"getprop magisk.version"
)));
magiskVersion
.
setText
(
getString
(
R
.
string
.
magisk_version
,
execute
(
"getprop magisk.version"
)));
selinuxStatus
.
setText
(
selinux
);
selinuxStatus
.
setText
(
selinux
);
assert
selinux
!=
null
;
if
(
selinux
.
equals
(
"Enforcing"
))
{
if
(
selinux
.
equals
(
"Enforcing"
))
{
selinuxStatus
.
setTextColor
(
Color
.
GREEN
);
selinuxStatus
.
setTextColor
(
Color
.
GREEN
);
selinuxToggle
.
setChecked
(
true
);
selinuxToggle
.
setChecked
(
true
);
...
@@ -109,7 +77,7 @@ public class MainActivity extends Activity {
...
@@ -109,7 +77,7 @@ public class MainActivity extends Activity {
safetyNet
.
setTextColor
(
Color
.
RED
);
safetyNet
.
setTextColor
(
Color
.
RED
);
rootToggle
.
setChecked
(
true
);
rootToggle
.
setChecked
(
true
);
if
(!
(
new
File
(
suPath
+
"/su"
)
).
exists
())
{
if
(!
new
File
(
suPath
+
"/su"
).
exists
())
{
rootStatus
.
setText
(
R
.
string
.
root_system
);
rootStatus
.
setText
(
R
.
string
.
root_system
);
safetyNet
.
setText
(
R
.
string
.
root_system_info
);
safetyNet
.
setText
(
R
.
string
.
root_system_info
);
rootToggle
.
setEnabled
(
false
);
rootToggle
.
setEnabled
(
false
);
...
@@ -135,29 +103,4 @@ public class MainActivity extends Activity {
...
@@ -135,29 +103,4 @@ public class MainActivity extends Activity {
}
}
}
}
protected
class
SU
extends
AsyncTask
<
String
,
Void
,
Void
>
{
@Override
protected
Void
doInBackground
(
String
...
params
)
{
try
{
Process
su
=
Runtime
.
getRuntime
().
exec
(
suPath
+
"/su"
);
DataOutputStream
out
=
new
DataOutputStream
(
su
.
getOutputStream
());
for
(
String
command
:
params
)
{
out
.
writeBytes
(
command
+
"\n"
);
out
.
flush
();
}
out
.
writeBytes
(
"exit\n"
);
out
.
flush
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
return
null
;
}
@Override
protected
void
onPostExecute
(
Void
aVoid
)
{
final
Handler
handler
=
new
Handler
();
handler
.
postDelayed
(
MainActivity
.
this
::
updateStatus
,
1500
);
}
}
}
}
app/src/main/java/com/topjohnwu/magisk/ModulesActivity.java
→
app/src/main/java/com/topjohnwu/magisk/
ui/
ModulesActivity.java
View file @
4a48f59d
package
com
.
topjohnwu
.
magisk
;
package
com
.
topjohnwu
.
magisk
.
ui
;
import
android.annotation.SuppressLint
;
import
android.app.Activity
;
import
android.app.Activity
;
import
android.app.ProgressDialog
;
import
android.app.ProgressDialog
;
import
android.content.Context
;
import
android.os.AsyncTask
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
import
android.os.Bundle
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.ArrayAdapter
;
import
android.widget.ListView
;
import
android.widget.ListView
;
import
android.widget.TextView
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.model.Module
;
import
com.topjohnwu.magisk.rv.ModulesAdapter
;
import
java.io.File
;
import
java.io.File
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
...
@@ -90,49 +87,4 @@ public class ModulesActivity extends Activity {
...
@@ -90,49 +87,4 @@ public class ModulesActivity extends Activity {
}
}
}
}
private
class
ModulesAdapter
extends
ArrayAdapter
<
Module
>
{
public
ModulesAdapter
(
Context
context
,
int
resource
,
List
<
Module
>
modules
)
{
super
(
context
,
resource
,
modules
);
}
@SuppressLint
(
"SetTextI18n"
)
@Override
public
View
getView
(
int
position
,
View
convertView
,
ViewGroup
parent
)
{
ViewHolder
vh
;
if
(
convertView
==
null
)
{
LayoutInflater
inflater
=
(
LayoutInflater
)
getContext
().
getSystemService
(
Context
.
LAYOUT_INFLATER_SERVICE
);
convertView
=
inflater
.
inflate
(
R
.
layout
.
row
,
null
);
vh
=
new
ViewHolder
();
vh
.
name
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
name
);
vh
.
version
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
version
);
vh
.
versionCode
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
versionCode
);
vh
.
description
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
description
);
vh
.
cache
=
(
TextView
)
convertView
.
findViewById
(
R
.
id
.
cache
);
convertView
.
setTag
(
vh
);
}
else
{
vh
=
(
ViewHolder
)
convertView
.
getTag
();
}
Module
module
=
getItem
(
position
);
vh
.
name
.
setText
(
"name= "
+
module
.
getName
());
vh
.
version
.
setText
(
"version= "
+
module
.
getVersion
());
vh
.
versionCode
.
setText
(
"versioncode= "
+
module
.
getVersionCode
());
vh
.
description
.
setText
(
"description= "
+
module
.
getDescription
());
vh
.
cache
.
setText
(
"is from cache= "
+
module
.
isCache
());
return
convertView
;
}
private
class
ViewHolder
{
public
TextView
name
;
public
TextView
version
;
public
TextView
versionCode
;
public
TextView
description
;
public
TextView
cache
;
}
}
}
}
app/src/main/java/com/topjohnwu/magisk/ui/utils/Utils.java
0 → 100644
View file @
4a48f59d
package
com
.
topjohnwu
.
magisk
.
ui
.
utils
;
import
org.sufficientlysecure.rootcommands.Shell
;
import
org.sufficientlysecure.rootcommands.command.SimpleCommand
;
import
java.io.IOException
;
import
java.util.concurrent.TimeoutException
;
public
class
Utils
{
public
static
String
executeCommand
(
String
...
commands
)
{
try
{
Shell
shell
=
Shell
.
startRootShell
();
SimpleCommand
command
=
new
SimpleCommand
(
commands
);
shell
.
add
(
command
).
waitForFinish
();
String
output
=
command
.
getOutput
();
output
=
output
.
replaceAll
(
"\n"
,
""
);
shell
.
close
();
return
output
;
}
catch
(
IOException
|
TimeoutException
e
)
{
return
""
;
}
}
}
app/src/main/res/layout/activity_main.xml
View file @
4a48f59d
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_height=
"match_parent"
android:focusableInTouchMode=
"true"
android:focusableInTouchMode=
"true"
tools:context=
"
com.topjohnwu.magisk
.MainActivity"
>
tools:context=
"
.ui
.MainActivity"
>
<TextView
<TextView
android:id=
"@+id/magisk_label"
android:id=
"@+id/magisk_label"
...
...
app/src/main/res/layout/activity_modules.xml
View file @
4a48f59d
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
xmlns:tools=
"http://schemas.android.com/tools"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_height=
"match_parent"
tools:context=
"
com.topjohnwu.magisk
.ModulesActivity"
>
tools:context=
"
.ui
.ModulesActivity"
>
<ListView
<ListView
android:id=
"@android:id/list"
android:id=
"@android:id/list"
...
...
app/src/test/java/com/topjohnwu/magisk/ExampleUnitTest.java
deleted
100644 → 0
View file @
bc2c63bf
package
com
.
topjohnwu
.
magisk
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public
class
ExampleUnitTest
{
@Test
public
void
addition_isCorrect
()
throws
Exception
{
assertEquals
(
4
,
2
+
2
);
}
}
\ No newline at end of file
lib/RootCommands/.gitignore
0 → 100644
View file @
4a48f59d
build/
*.iml
\ No newline at end of file
lib/RootCommands/build.gradle
0 → 100644
View file @
4a48f59d
apply
plugin:
'com.android.library'
buildscript
{
repositories
{
mavenCentral
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.1.3'
}
}
android
{
compileSdkVersion
24
buildToolsVersion
"24.0.1"
defaultConfig
{
minSdkVersion
7
targetSdkVersion
24
}
}
lib/RootCommands/src/main/AndroidManifest.xml
0 → 100644
View file @
4a48f59d
<?xml version="1.0" encoding="utf-8"?>
<manifest
package=
"org.sufficientlysecure.rootcommands"
>
<application/>
</manifest>
\ No newline at end of file
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/Mount.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (c) 2012 Stephen Erickson, Chris Ravenscroft, Adam Shanks (RootTools)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
;
import
java.io.File
;
import
java.util.Arrays
;
import
java.util.HashSet
;
import
java.util.Set
;
public
class
Mount
{
protected
final
File
mDevice
;
protected
final
File
mMountPoint
;
protected
final
String
mType
;
protected
final
Set
<
String
>
mFlags
;
Mount
(
File
device
,
File
path
,
String
type
,
String
flagsStr
)
{
mDevice
=
device
;
mMountPoint
=
path
;
mType
=
type
;
mFlags
=
new
HashSet
<
String
>(
Arrays
.
asList
(
flagsStr
.
split
(
","
)));
}
public
File
getDevice
()
{
return
mDevice
;
}
public
File
getMountPoint
()
{
return
mMountPoint
;
}
public
String
getType
()
{
return
mType
;
}
public
Set
<
String
>
getFlags
()
{
return
mFlags
;
}
@Override
public
String
toString
()
{
return
String
.
format
(
"%s on %s type %s %s"
,
mDevice
,
mMountPoint
,
mType
,
mFlags
);
}
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/Remounter.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (c) 2012 Stephen Erickson, Chris Ravenscroft, Adam Shanks (RootTools)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
;
import
org.sufficientlysecure.rootcommands.command.SimpleCommand
;
import
org.sufficientlysecure.rootcommands.util.Log
;
import
java.io.File
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.io.LineNumberReader
;
import
java.util.ArrayList
;
import
java.util.Locale
;
//no modifier, this means it is package-private. Only our internal classes can use this.
class
Remounter
{
private
Shell
shell
;
public
Remounter
(
Shell
shell
)
{
super
();
this
.
shell
=
shell
;
}
/**
* This will return an ArrayList of the class Mount. The class mount contains the following
* property's: device mountPoint type flags
* <p>
* These will provide you with any information you need to work with the mount points.
*
* @return <code>ArrayList<Mount></code> an ArrayList of the class Mount.
* @throws Exception if we cannot return the mount points.
*/
protected
static
ArrayList
<
Mount
>
getMounts
()
throws
Exception
{
final
String
tempFile
=
"/data/local/RootToolsMounts"
;
// copy /proc/mounts to tempfile. Directly reading it does not work on 4.3
Shell
shell
=
Shell
.
startRootShell
();
Toolbox
tb
=
new
Toolbox
(
shell
);
tb
.
copyFile
(
"/proc/mounts"
,
tempFile
,
false
,
false
);
tb
.
setFilePermissions
(
tempFile
,
"777"
);
shell
.
close
();
LineNumberReader
lnr
=
null
;
lnr
=
new
LineNumberReader
(
new
FileReader
(
tempFile
));
String
line
;
ArrayList
<
Mount
>
mounts
=
new
ArrayList
<
Mount
>();
while
((
line
=
lnr
.
readLine
())
!=
null
)
{
Log
.
d
(
RootCommands
.
TAG
,
line
);
String
[]
fields
=
line
.
split
(
" "
);
mounts
.
add
(
new
Mount
(
new
File
(
fields
[
0
]),
// device
new
File
(
fields
[
1
]),
// mountPoint
fields
[
2
],
// fstype
fields
[
3
]
// flags
));
}
lnr
.
close
();
return
mounts
;
}
/**
* This will take a path, which can contain the file name as well, and attempt to remount the
* underlying partition.
* <p>
* For example, passing in the following string:
* "/system/bin/some/directory/that/really/would/never/exist" will result in /system ultimately
* being remounted. However, keep in mind that the longer the path you supply, the more work
* this has to do, and the slower it will run.
*
* @param file file path
* @param mountType mount type: pass in RO (Read only) or RW (Read Write)
* @return a <code>boolean</code> which indicates whether or not the partition has been
* remounted as specified.
*/
protected
boolean
remount
(
String
file
,
String
mountType
)
{
// if the path has a trailing slash get rid of it.
if
(
file
.
endsWith
(
"/"
)
&&
!
file
.
equals
(
"/"
))
{
file
=
file
.
substring
(
0
,
file
.
lastIndexOf
(
"/"
));
}
// Make sure that what we are trying to remount is in the mount list.
boolean
foundMount
=
false
;
while
(!
foundMount
)
{
try
{
for
(
Mount
mount
:
getMounts
())
{
Log
.
d
(
RootCommands
.
TAG
,
mount
.
getMountPoint
().
toString
());
if
(
file
.
equals
(
mount
.
getMountPoint
().
toString
()))
{
foundMount
=
true
;
break
;
}
}
}
catch
(
Exception
e
)
{
Log
.
e
(
RootCommands
.
TAG
,
"Exception"
,
e
);
return
false
;
}
if
(!
foundMount
)
{
try
{
file
=
(
new
File
(
file
).
getParent
()).
toString
();
}
catch
(
Exception
e
)
{
Log
.
e
(
RootCommands
.
TAG
,
"Exception"
,
e
);
return
false
;
}
}
}
Mount
mountPoint
=
findMountPointRecursive
(
file
);
Log
.
d
(
RootCommands
.
TAG
,
"Remounting "
+
mountPoint
.
getMountPoint
().
getAbsolutePath
()
+
" as "
+
mountType
.
toLowerCase
(
Locale
.
US
));
final
boolean
isMountMode
=
mountPoint
.
getFlags
().
contains
(
mountType
.
toLowerCase
(
Locale
.
US
));
if
(!
isMountMode
)
{
// grab an instance of the internal class
try
{
SimpleCommand
command
=
new
SimpleCommand
(
"busybox mount -o remount,"
+
mountType
.
toLowerCase
(
Locale
.
US
)
+
" "
+
mountPoint
.
getDevice
().
getAbsolutePath
()
+
" "
+
mountPoint
.
getMountPoint
().
getAbsolutePath
(),
"toolbox mount -o remount,"
+
mountType
.
toLowerCase
(
Locale
.
US
)
+
" "
+
mountPoint
.
getDevice
().
getAbsolutePath
()
+
" "
+
mountPoint
.
getMountPoint
().
getAbsolutePath
(),
"mount -o remount,"
+
mountType
.
toLowerCase
(
Locale
.
US
)
+
" "
+
mountPoint
.
getDevice
().
getAbsolutePath
()
+
" "
+
mountPoint
.
getMountPoint
().
getAbsolutePath
(),
"/system/bin/toolbox mount -o remount,"
+
mountType
.
toLowerCase
(
Locale
.
US
)
+
" "
+
mountPoint
.
getDevice
().
getAbsolutePath
()
+
" "
+
mountPoint
.
getMountPoint
().
getAbsolutePath
());
// execute on shell
shell
.
add
(
command
).
waitForFinish
();
}
catch
(
Exception
e
)
{
}
mountPoint
=
findMountPointRecursive
(
file
);
}
if
(
mountPoint
!=
null
)
{
Log
.
d
(
RootCommands
.
TAG
,
mountPoint
.
getFlags
()
+
" AND "
+
mountType
.
toLowerCase
(
Locale
.
US
));
if
(
mountPoint
.
getFlags
().
contains
(
mountType
.
toLowerCase
(
Locale
.
US
)))
{
Log
.
d
(
RootCommands
.
TAG
,
mountPoint
.
getFlags
().
toString
());
return
true
;
}
else
{
Log
.
d
(
RootCommands
.
TAG
,
mountPoint
.
getFlags
().
toString
());
}
}
else
{
Log
.
d
(
RootCommands
.
TAG
,
"mountPoint is null"
);
}
return
false
;
}
private
Mount
findMountPointRecursive
(
String
file
)
{
try
{
ArrayList
<
Mount
>
mounts
=
getMounts
();
for
(
File
path
=
new
File
(
file
);
path
!=
null
;
)
{
for
(
Mount
mount
:
mounts
)
{
if
(
mount
.
getMountPoint
().
equals
(
path
))
{
return
mount
;
}
}
}
return
null
;
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
Exception
e
)
{
Log
.
e
(
RootCommands
.
TAG
,
"Exception"
,
e
);
}
return
null
;
}
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/RootCommands.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
;
import
org.sufficientlysecure.rootcommands.util.Log
;
public
class
RootCommands
{
public
static
final
String
TAG
=
"RootCommands"
;
public
static
boolean
DEBUG
=
false
;
public
static
int
DEFAULT_TIMEOUT
=
10000
;
/**
* General method to check if user has su binary and accepts root access for this program!
*
* @return true if everything worked
*/
public
static
boolean
rootAccessGiven
()
{
boolean
rootAccess
=
false
;
try
{
Shell
rootShell
=
Shell
.
startRootShell
();
Toolbox
tb
=
new
Toolbox
(
rootShell
);
if
(
tb
.
isRootAccessGiven
())
{
rootAccess
=
true
;
}
rootShell
.
close
();
}
catch
(
Exception
e
)
{
Log
.
e
(
TAG
,
"Problem while checking for root access!"
,
e
);
}
return
rootAccess
;
}
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/Shell.java
0 → 100644
View file @
4a48f59d
This diff is collapsed.
Click to expand it.
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/SystemCommands.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
;
import
android.annotation.TargetApi
;
import
android.content.ContentResolver
;
import
android.content.Context
;
import
android.location.LocationManager
;
import
android.os.PowerManager
;
import
android.provider.Settings
;
/**
* This methods work when the apk is installed as a system app (under /system/app)
*/
public
class
SystemCommands
{
Context
context
;
public
SystemCommands
(
Context
context
)
{
super
();
this
.
context
=
context
;
}
/**
* Get GPS status
*/
public
boolean
getGPS
()
{
return
((
LocationManager
)
context
.
getSystemService
(
Context
.
LOCATION_SERVICE
))
.
isProviderEnabled
(
LocationManager
.
GPS_PROVIDER
);
}
/**
* Enable/Disable GPS
*
* @param value
*/
@TargetApi
(
8
)
public
void
setGPS
(
boolean
value
)
{
ContentResolver
localContentResolver
=
context
.
getContentResolver
();
Settings
.
Secure
.
setLocationProviderEnabled
(
localContentResolver
,
LocationManager
.
GPS_PROVIDER
,
value
);
}
/**
* TODO: Not ready yet
*/
@TargetApi
(
8
)
public
void
reboot
()
{
PowerManager
pm
=
(
PowerManager
)
context
.
getSystemService
(
Context
.
POWER_SERVICE
);
pm
.
reboot
(
"recovery"
);
pm
.
reboot
(
null
);
// not working:
// reboot(null);
}
/**
* Reboot the device immediately, passing 'reason' (may be null) to the underlying __reboot
* system call. Should not return.
*
* Taken from com.android.server.PowerManagerService.reboot
*/
// public void reboot(String reason) {
//
// // final String finalReason = reason;
// Runnable runnable = new Runnable() {
// public void run() {
// synchronized (this) {
// // ShutdownThread.reboot(mContext, finalReason, false);
// try {
// Class<?> clazz = Class.forName("com.android.internal.app.ShutdownThread");
//
// // if (mReboot) {
// Method method = clazz.getMethod("reboot", Context.class, String.class,
// Boolean.TYPE);
// method.invoke(null, context, null, false);
//
// // if (mReboot) {
// // Method method = clazz.getMethod("reboot", Context.class, String.class,
// // Boolean.TYPE);
// // method.invoke(null, mContext, mReason, mConfirm);
// // } else {
// // Method method = clazz.getMethod("shutdown", Context.class, Boolean.TYPE);
// // method.invoke(null, mContext, mConfirm);
// // }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
//
// }
// };
// // ShutdownThread must run on a looper capable of displaying the UI.
// mHandler.post(runnable);
//
// // PowerManager.reboot() is documented not to return so just wait for the inevitable.
// // synchronized (runnable) {
// // while (true) {
// // try {
// // runnable.wait();
// // } catch (InterruptedException e) {
// // }
// // }
// // }
// }
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/Toolbox.java
0 → 100644
View file @
4a48f59d
This diff is collapsed.
Click to expand it.
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/command/Command.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (c) 2012 Stephen Erickson, Chris Ravenscroft, Adam Shanks, Jeremy Lakeman (RootTools)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
command
;
import
org.sufficientlysecure.rootcommands.RootCommands
;
import
org.sufficientlysecure.rootcommands.Shell
;
import
org.sufficientlysecure.rootcommands.util.BrokenBusyboxException
;
import
org.sufficientlysecure.rootcommands.util.Log
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.util.concurrent.TimeoutException
;
public
abstract
class
Command
{
final
String
command
[];
boolean
finished
=
false
;
boolean
brokenBusyboxDetected
=
false
;
int
exitCode
;
int
id
;
int
timeout
=
RootCommands
.
DEFAULT_TIMEOUT
;
Shell
shell
=
null
;
public
Command
(
String
...
command
)
{
this
.
command
=
command
;
}
public
Command
(
int
timeout
,
String
...
command
)
{
this
.
command
=
command
;
this
.
timeout
=
timeout
;
}
/**
* This is called from Shell after adding it
*
* @param shell
* @param id
*/
public
void
addedToShell
(
Shell
shell
,
int
id
)
{
this
.
shell
=
shell
;
this
.
id
=
id
;
}
/**
* Gets command string executed on the shell
*
* @return
*/
public
String
getCommand
()
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
command
.
length
;
i
++)
{
// redirect stderr to stdout
sb
.
append
(
command
[
i
]
+
" 2>&1"
);
sb
.
append
(
'\n'
);
}
Log
.
d
(
RootCommands
.
TAG
,
"Sending command(s): "
+
sb
.
toString
());
return
sb
.
toString
();
}
public
void
writeCommand
(
OutputStream
out
)
throws
IOException
{
out
.
write
(
getCommand
().
getBytes
());
}
public
void
processOutput
(
String
line
)
{
Log
.
d
(
RootCommands
.
TAG
,
"ID: "
+
id
+
", Output: "
+
line
);
/*
* Try to detect broken toolbox/busybox binaries (see
* https://code.google.com/p/busybox-android/issues/detail?id=1)
*
* It is giving "Value too large for defined data type" on certain file operations (e.g. ls
* and chown) in certain directories (e.g. /data/data)
*/
if
(
line
.
contains
(
"Value too large for defined data type"
))
{
Log
.
e
(
RootCommands
.
TAG
,
"Busybox is broken with high probability due to line: "
+
line
);
brokenBusyboxDetected
=
true
;
}
// now execute specific output parsing
output
(
id
,
line
);
}
public
abstract
void
output
(
int
id
,
String
line
);
public
void
processAfterExecution
(
int
exitCode
)
{
Log
.
d
(
RootCommands
.
TAG
,
"ID: "
+
id
+
", ExitCode: "
+
exitCode
);
afterExecution
(
id
,
exitCode
);
}
public
abstract
void
afterExecution
(
int
id
,
int
exitCode
);
public
void
commandFinished
(
int
id
)
{
Log
.
d
(
RootCommands
.
TAG
,
"Command "
+
id
+
" finished."
);
}
public
void
setExitCode
(
int
code
)
{
synchronized
(
this
)
{
exitCode
=
code
;
finished
=
true
;
commandFinished
(
id
);
this
.
notifyAll
();
}
}
/**
* Close the shell
*
* @param reason
*/
public
void
terminate
(
String
reason
)
{
try
{
shell
.
close
();
Log
.
d
(
RootCommands
.
TAG
,
"Terminating the shell."
);
terminated
(
reason
);
}
catch
(
IOException
e
)
{
}
}
public
void
terminated
(
String
reason
)
{
setExitCode
(-
1
);
Log
.
d
(
RootCommands
.
TAG
,
"Command "
+
id
+
" did not finish, because of "
+
reason
);
}
/**
* Waits for this command to finish and forwards exitCode into afterExecution method
*
* @throws TimeoutException
* @throws BrokenBusyboxException
*/
public
void
waitForFinish
()
throws
TimeoutException
,
BrokenBusyboxException
{
synchronized
(
this
)
{
while
(!
finished
)
{
try
{
this
.
wait
(
timeout
);
}
catch
(
InterruptedException
e
)
{
Log
.
e
(
RootCommands
.
TAG
,
"InterruptedException in waitForFinish()"
,
e
);
}
if
(!
finished
)
{
finished
=
true
;
terminate
(
"Timeout"
);
throw
new
TimeoutException
(
"Timeout has occurred."
);
}
}
if
(
brokenBusyboxDetected
)
{
throw
new
BrokenBusyboxException
();
}
processAfterExecution
(
exitCode
);
}
}
}
\ No newline at end of file
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/command/ExecutableCommand.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
command
;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.os.Build
;
import
java.io.File
;
public
abstract
class
ExecutableCommand
extends
Command
{
public
static
final
String
EXECUTABLE_PREFIX
=
"lib"
;
public
static
final
String
EXECUTABLE_SUFFIX
=
"_exec.so"
;
/**
* This class provides a way to use your own binaries!
* <p>
* Include your own executables, renamed from * to lib*_exec.so, in your libs folder under the
* architecture directories. Now they will be deployed by Android the same way libraries are
* deployed!
* <p>
* See README for more information how to use your own executables!
*
* @param context
* @param executableName
* @param parameters
*/
public
ExecutableCommand
(
Context
context
,
String
executableName
,
String
parameters
)
{
super
(
getLibDirectory
(
context
)
+
File
.
separator
+
EXECUTABLE_PREFIX
+
executableName
+
EXECUTABLE_SUFFIX
+
" "
+
parameters
);
}
/**
* Get full path to lib directory of app
*
* @return dir as String
*/
@SuppressLint
(
"NewApi"
)
private
static
String
getLibDirectory
(
Context
context
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
9
)
{
return
context
.
getApplicationInfo
().
nativeLibraryDir
;
}
else
{
return
context
.
getApplicationInfo
().
dataDir
+
File
.
separator
+
"lib"
;
}
}
public
abstract
void
output
(
int
id
,
String
line
);
public
abstract
void
afterExecution
(
int
id
,
int
exitCode
);
}
\ No newline at end of file
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/command/SimpleCommand.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
command
;
public
class
SimpleCommand
extends
Command
{
private
StringBuilder
sb
=
new
StringBuilder
();
public
SimpleCommand
(
String
...
command
)
{
super
(
command
);
}
@Override
public
void
output
(
int
id
,
String
line
)
{
sb
.
append
(
line
).
append
(
'\n'
);
}
@Override
public
void
afterExecution
(
int
id
,
int
exitCode
)
{
}
public
String
getOutput
()
{
return
sb
.
toString
();
}
public
int
getExitCode
()
{
return
exitCode
;
}
}
\ No newline at end of file
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/command/SimpleExecutableCommand.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
command
;
import
android.content.Context
;
public
class
SimpleExecutableCommand
extends
ExecutableCommand
{
private
StringBuilder
sb
=
new
StringBuilder
();
public
SimpleExecutableCommand
(
Context
context
,
String
executableName
,
String
parameters
)
{
super
(
context
,
executableName
,
parameters
);
}
@Override
public
void
output
(
int
id
,
String
line
)
{
sb
.
append
(
line
).
append
(
'\n'
);
}
@Override
public
void
afterExecution
(
int
id
,
int
exitCode
)
{
}
public
String
getOutput
()
{
return
sb
.
toString
();
}
public
int
getExitCode
()
{
return
exitCode
;
}
}
\ No newline at end of file
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/util/BrokenBusyboxException.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
util
;
import
java.io.IOException
;
public
class
BrokenBusyboxException
extends
IOException
{
private
static
final
long
serialVersionUID
=
8337358201589488409L
;
public
BrokenBusyboxException
()
{
super
();
}
public
BrokenBusyboxException
(
String
detailMessage
)
{
super
(
detailMessage
);
}
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/util/Log.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
util
;
import
org.sufficientlysecure.rootcommands.RootCommands
;
/**
* Wraps Android Logging to enable or disable debug output using Constants
*/
public
final
class
Log
{
public
static
void
v
(
String
tag
,
String
msg
)
{
if
(
RootCommands
.
DEBUG
)
{
android
.
util
.
Log
.
v
(
tag
,
msg
);
}
}
public
static
void
v
(
String
tag
,
String
msg
,
Throwable
tr
)
{
if
(
RootCommands
.
DEBUG
)
{
android
.
util
.
Log
.
v
(
tag
,
msg
,
tr
);
}
}
public
static
void
d
(
String
tag
,
String
msg
)
{
if
(
RootCommands
.
DEBUG
)
{
android
.
util
.
Log
.
d
(
tag
,
msg
);
}
}
public
static
void
d
(
String
tag
,
String
msg
,
Throwable
tr
)
{
if
(
RootCommands
.
DEBUG
)
{
android
.
util
.
Log
.
d
(
tag
,
msg
,
tr
);
}
}
public
static
void
i
(
String
tag
,
String
msg
)
{
if
(
RootCommands
.
DEBUG
)
{
android
.
util
.
Log
.
i
(
tag
,
msg
);
}
}
public
static
void
i
(
String
tag
,
String
msg
,
Throwable
tr
)
{
if
(
RootCommands
.
DEBUG
)
{
android
.
util
.
Log
.
i
(
tag
,
msg
,
tr
);
}
}
public
static
void
w
(
String
tag
,
String
msg
)
{
android
.
util
.
Log
.
w
(
tag
,
msg
);
}
public
static
void
w
(
String
tag
,
String
msg
,
Throwable
tr
)
{
android
.
util
.
Log
.
w
(
tag
,
msg
,
tr
);
}
public
static
void
w
(
String
tag
,
Throwable
tr
)
{
android
.
util
.
Log
.
w
(
tag
,
tr
);
}
public
static
void
e
(
String
tag
,
String
msg
)
{
android
.
util
.
Log
.
e
(
tag
,
msg
);
}
public
static
void
e
(
String
tag
,
String
msg
,
Throwable
tr
)
{
android
.
util
.
Log
.
e
(
tag
,
msg
,
tr
);
}
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/util/RootAccessDeniedException.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
util
;
import
java.io.IOException
;
public
class
RootAccessDeniedException
extends
IOException
{
private
static
final
long
serialVersionUID
=
9088998884166225540L
;
public
RootAccessDeniedException
()
{
super
();
}
public
RootAccessDeniedException
(
String
detailMessage
)
{
super
(
detailMessage
);
}
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/util/UnsupportedArchitectureException.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
util
;
public
class
UnsupportedArchitectureException
extends
Exception
{
private
static
final
long
serialVersionUID
=
7826528799780001655L
;
public
UnsupportedArchitectureException
()
{
super
();
}
public
UnsupportedArchitectureException
(
String
detailMessage
)
{
super
(
detailMessage
);
}
}
lib/RootCommands/src/main/java/org/sufficientlysecure/rootcommands/util/Utils.java
0 → 100644
View file @
4a48f59d
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (c) 2012 Michael Elsdörfer (Android Autostarts)
* Copyright (c) 2012 Stephen Erickson, Chris Ravenscroft, Adam Shanks (RootTools)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
sufficientlysecure
.
rootcommands
.
util
;
import
org.sufficientlysecure.rootcommands.RootCommands
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Map
;
public
class
Utils
{
/*
* The emulator and ADP1 device both have a su binary in /system/xbin/su, but it doesn't allow
* apps to use it (su app_29 $ su su: uid 10029 not allowed to su).
*
* Cyanogen used to have su in /system/bin/su, in newer versions it's a symlink to
* /system/xbin/su.
*
* The Archos tablet has it in /data/bin/su, since they don't have write access to /system yet.
*/
static
final
String
[]
BinaryPlaces
=
{
"/data/bin/"
,
"/system/bin/"
,
"/system/xbin/"
,
"/sbin/"
,
"/data/local/xbin/"
,
"/data/local/bin/"
,
"/system/sd/xbin/"
,
"/system/bin/failsafe/"
,
"/data/local/"
};
/**
* Determine the path of the su executable.
* <p>
* Code from https://github.com/miracle2k/android-autostarts, use under Apache License was
* agreed by Michael Elsdörfer
*/
public
static
String
getSuPath
()
{
for
(
String
p
:
BinaryPlaces
)
{
File
su
=
new
File
(
p
+
"su"
);
if
(
su
.
exists
())
{
Log
.
d
(
RootCommands
.
TAG
,
"su found at: "
+
p
);
return
su
.
getAbsolutePath
();
}
else
{
Log
.
v
(
RootCommands
.
TAG
,
"No su in: "
+
p
);
}
}
Log
.
d
(
RootCommands
.
TAG
,
"No su found in a well-known location, "
+
"will just use \"su\"."
);
return
"su"
;
}
/**
* This code is adapted from java.lang.ProcessBuilder.start().
* <p>
* The problem is that Android doesn't allow us to modify the map returned by
* ProcessBuilder.environment(), even though the docstring indicates that it should. This is
* because it simply returns the SystemEnvironment object that System.getenv() gives us. The
* relevant portion in the source code is marked as "// android changed", so presumably it's not
* the case in the original version of the Apache Harmony project.
* <p>
* Note that simply passing the environment variables we want to Process.exec won't be good
* enough, since that would override the environment we inherited completely.
* <p>
* We needed to be able to set a CLASSPATH environment variable for our new process in order to
* use the "app_process" command directly. Note: "app_process" takes arguments passed on to the
* Dalvik VM as well; this might be an alternative way to set the class path.
* <p>
* Code from https://github.com/miracle2k/android-autostarts, use under Apache License was
* agreed by Michael Elsdörfer
*/
public
static
Process
runWithEnv
(
String
command
,
ArrayList
<
String
>
customAddedEnv
,
String
baseDirectory
)
throws
IOException
{
Map
<
String
,
String
>
environment
=
System
.
getenv
();
String
[]
envArray
=
new
String
[
environment
.
size
()
+
(
customAddedEnv
!=
null
?
customAddedEnv
.
size
()
:
0
)];
int
i
=
0
;
for
(
Map
.
Entry
<
String
,
String
>
entry
:
environment
.
entrySet
())
{
envArray
[
i
++]
=
entry
.
getKey
()
+
"="
+
entry
.
getValue
();
}
if
(
customAddedEnv
!=
null
)
{
for
(
String
entry
:
customAddedEnv
)
{
envArray
[
i
++]
=
entry
;
}
}
Process
process
;
if
(
baseDirectory
==
null
)
{
process
=
Runtime
.
getRuntime
().
exec
(
command
,
envArray
,
null
);
}
else
{
process
=
Runtime
.
getRuntime
().
exec
(
command
,
envArray
,
new
File
(
baseDirectory
));
}
return
process
;
}
}
settings.gradle
View file @
4a48f59d
include
':app'
include
':app'
,
':lib:RootCommands'
\ No newline at end of file
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