PageRenderTime 1343ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/F-Droid/src/org/fdroid/fdroid/installer/RootInstaller.java

https://gitlab.com/taghiahmadi02/fdroidclient
Java | 223 lines | 130 code | 30 blank | 63 comment | 16 complexity | 1abcb62fcf188b002301c16ce418ebef MD5 | raw file
  1. /*
  2. * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 3
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  17. * MA 02110-1301, USA.
  18. */
  19. package org.fdroid.fdroid.installer;
  20. import android.content.Context;
  21. import android.content.Intent;
  22. import android.content.pm.PackageManager;
  23. import android.util.Log;
  24. import eu.chainfire.libsuperuser.Shell;
  25. import java.io.File;
  26. import java.util.ArrayList;
  27. import java.util.List;
  28. /**
  29. * Installer using a root shell and "pm install", "pm uninstall" commands
  30. */
  31. public class RootInstaller extends Installer {
  32. Shell.Interactive rootSession;
  33. public RootInstaller(Context context, PackageManager pm, InstallerCallback callback)
  34. throws AndroidNotCompatibleException {
  35. super(context, pm, callback);
  36. }
  37. private Shell.Builder createShellBuilder() {
  38. Shell.Builder shellBuilder = new Shell.Builder()
  39. .useSU()
  40. .setWantSTDERR(true)
  41. .setWatchdogTimeout(30)
  42. .setMinimalLogging(false);
  43. return shellBuilder;
  44. }
  45. @Override
  46. protected void installPackageInternal(final File apkFile) throws AndroidNotCompatibleException {
  47. rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() {
  48. // Callback to report whether the shell was successfully
  49. // started up
  50. @Override
  51. public void onCommandResult(int commandCode, int exitCode, List<String> output) {
  52. if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) {
  53. // NOTE: Additional exit codes:
  54. // Shell.OnCommandResultListener.SHELL_WRONG_UID
  55. // Shell.OnCommandResultListener.SHELL_EXEC_FAILED
  56. Log.e(TAG, "Error opening root shell with exitCode " + exitCode);
  57. mCallback.onError(InstallerCallback.OPERATION_INSTALL,
  58. InstallerCallback.ERROR_CODE_OTHER);
  59. } else {
  60. addInstallCommand(apkFile);
  61. }
  62. }
  63. });
  64. }
  65. @Override
  66. protected void installPackageInternal(final List<File> apkFiles)
  67. throws AndroidNotCompatibleException {
  68. rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() {
  69. // Callback to report whether the shell was successfully
  70. // started up
  71. @Override
  72. public void onCommandResult(int commandCode, int exitCode, List<String> output) {
  73. if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) {
  74. // NOTE: Additional exit codes:
  75. // Shell.OnCommandResultListener.SHELL_WRONG_UID
  76. // Shell.OnCommandResultListener.SHELL_EXEC_FAILED
  77. Log.e(TAG, "Error opening root shell with exitCode " + exitCode);
  78. mCallback.onError(InstallerCallback.OPERATION_INSTALL,
  79. InstallerCallback.ERROR_CODE_OTHER);
  80. } else {
  81. addInstallCommand(apkFiles);
  82. }
  83. }
  84. });
  85. }
  86. @Override
  87. protected void deletePackageInternal(final String packageName)
  88. throws AndroidNotCompatibleException {
  89. rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() {
  90. // Callback to report whether the shell was successfully
  91. // started up
  92. @Override
  93. public void onCommandResult(int commandCode, int exitCode, List<String> output) {
  94. if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) {
  95. // NOTE: Additional exit codes:
  96. // Shell.OnCommandResultListener.SHELL_WRONG_UID
  97. // Shell.OnCommandResultListener.SHELL_EXEC_FAILED
  98. Log.e(TAG, "Error opening root shell with exitCode " + exitCode);
  99. mCallback.onError(InstallerCallback.OPERATION_DELETE,
  100. InstallerCallback.ERROR_CODE_OTHER);
  101. } else {
  102. addDeleteCommand(packageName);
  103. }
  104. }
  105. });
  106. }
  107. @Override
  108. public boolean handleOnActivityResult(int requestCode, int resultCode, Intent data) {
  109. // no need to handle onActivityResult
  110. return false;
  111. }
  112. private void addInstallCommand(File apkFile) {
  113. rootSession.addCommand("pm install -r " + apkFile.getAbsolutePath(), 0,
  114. new Shell.OnCommandResultListener() {
  115. public void onCommandResult(int commandCode, int exitCode, List<String> output) {
  116. // close su shell
  117. rootSession.close();
  118. if (exitCode < 0) {
  119. Log.e(TAG, "Install failed with exit code " + exitCode);
  120. mCallback.onError(InstallerCallback.OPERATION_INSTALL,
  121. InstallerCallback.ERROR_CODE_OTHER);
  122. } else {
  123. mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL);
  124. }
  125. }
  126. });
  127. }
  128. private void addInstallCommand(List<File> apkFiles) {
  129. List<String> commands = new ArrayList<String>();
  130. String pm = "pm install -r ";
  131. for (File apkFile : apkFiles) {
  132. commands.add(pm + apkFile.getAbsolutePath());
  133. }
  134. rootSession.addCommand(commands, 0,
  135. new Shell.OnCommandResultListener() {
  136. public void onCommandResult(int commandCode, int exitCode,
  137. List<String> output) {
  138. // close su shell
  139. rootSession.close();
  140. if (exitCode < 0) {
  141. Log.e(TAG, "Install failed with exit code " + exitCode);
  142. mCallback.onError(InstallerCallback.OPERATION_INSTALL,
  143. InstallerCallback.ERROR_CODE_OTHER);
  144. } else {
  145. mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL);
  146. }
  147. }
  148. });
  149. }
  150. private void addDeleteCommand(String packageName) {
  151. rootSession.addCommand("pm uninstall " + packageName, 0,
  152. new Shell.OnCommandResultListener() {
  153. public void onCommandResult(int commandCode, int exitCode, List<String> output) {
  154. // close su shell
  155. rootSession.close();
  156. if (exitCode < 0) {
  157. Log.e(TAG, "Delete failed with exit code " + exitCode);
  158. mCallback.onError(InstallerCallback.OPERATION_DELETE,
  159. InstallerCallback.ERROR_CODE_OTHER);
  160. } else {
  161. mCallback.onSuccess(InstallerCallback.OPERATION_DELETE);
  162. }
  163. }
  164. });
  165. }
  166. @Override
  167. public boolean supportsUnattendedOperations() {
  168. return true;
  169. }
  170. /**
  171. * pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] [--algo
  172. * <algorithm name> --key <key-in-hex> --iv <IV-in-hex>] [--originating-uri
  173. * <URI>] [--referrer <URI>] PATH
  174. * <p/>
  175. * pm install: installs a package to the system.
  176. * <p/>
  177. * Options:<br/>
  178. * -l: install the package with FORWARD_LOCK.<br/>
  179. * -r: reinstall an existing app, keeping its data.<br/>
  180. * -t: allow test .apks to be installed.<br/>
  181. * -i: specify the installer package name.<br/>
  182. * -s: install package on sdcard.<br/>
  183. * -f: install package on internal flash.<br/>
  184. * -d: allow version code downgrade.<br/>
  185. * <p/>
  186. * pm uninstall [-k] PACKAGE
  187. * <p/>
  188. * pm uninstall: removes a package from the system.
  189. * <p/>
  190. * Options:<br/>
  191. * -k: keep the data and cache directories around after package removal.
  192. */
  193. }