diff options
author | Jorge Ruesga <jorge@ruesga.com> | 2013-03-22 01:07:01 +0100 |
---|---|---|
committer | Jorge Ruesga <jorge@ruesga.com> | 2013-03-22 01:07:01 +0100 |
commit | e9c9b1b5bd0c17a239eb5d8c10a4f5f8ce33a611 (patch) | |
tree | af04a9b66b2db37cfbda29748dcfe5099963b32d /src | |
parent | f2803c7506e37cdac33c8a0b6b4adf7994212a34 (diff) | |
download | android_packages_apps_CMFileManager-e9c9b1b5bd0c17a239eb5d8c10a4f5f8ce33a611.tar.gz android_packages_apps_CMFileManager-e9c9b1b5bd0c17a239eb5d8c10a4f5f8ce33a611.tar.bz2 android_packages_apps_CMFileManager-e9c9b1b5bd0c17a239eb5d8c10a4f5f8ce33a611.zip |
CMFM: Ask to gain privileges for asynchronous commands
Change-Id: I35c48174e2e6093ada8e45786fe9320193effb96
Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
Diffstat (limited to 'src')
7 files changed, 293 insertions, 106 deletions
diff --git a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java index df5751e1..21267bec 100644 --- a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java @@ -47,7 +47,6 @@ import android.widget.TextView; import android.widget.TextView.BufferType; import android.widget.Toast; -import com.cyanogenmod.filemanager.FileManagerApplication; import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.activities.preferences.SettingsPreferences; import com.cyanogenmod.filemanager.activities.preferences.SettingsPreferences.EditorPreferenceFragment; @@ -56,10 +55,7 @@ import com.cyanogenmod.filemanager.adapters.SimpleMenuListAdapter; import com.cyanogenmod.filemanager.commands.AsyncResultListener; import com.cyanogenmod.filemanager.commands.WriteExecutable; import com.cyanogenmod.filemanager.console.ConsoleBuilder; -import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; -import com.cyanogenmod.filemanager.console.RelaunchableException; import com.cyanogenmod.filemanager.model.FileSystemObject; -import com.cyanogenmod.filemanager.preferences.AccessMode; import com.cyanogenmod.filemanager.preferences.FileManagerSettings; import com.cyanogenmod.filemanager.preferences.Preferences; import com.cyanogenmod.filemanager.ui.ThemeManager; @@ -69,6 +65,8 @@ import com.cyanogenmod.filemanager.util.AndroidHelper; import com.cyanogenmod.filemanager.util.CommandHelper; import com.cyanogenmod.filemanager.util.DialogHelper; import com.cyanogenmod.filemanager.util.ExceptionUtil; +import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult; +import com.cyanogenmod.filemanager.util.FileHelper; import java.io.ByteArrayInputStream; import java.io.File; @@ -547,7 +545,7 @@ public class EditorActivity extends Activity implements TextWatcher { switch (view.getId()) { case R.id.ab_button1: // Save the file - writeFile(); + checkAndWrite(); break; case R.id.ab_button2: @@ -565,7 +563,7 @@ public class EditorActivity extends Activity implements TextWatcher { */ private boolean initializeConsole() { try { - ConsoleBuilder.createDefaultConsole(this); + ConsoleBuilder.getConsole(this); // There is a console allocated. Use it. return true; } catch (Throwable _throw) { @@ -609,7 +607,7 @@ public class EditorActivity extends Activity implements TextWatcher { File f = new File(path); this.mTitle.setText(f.getName()); - // Check that we have access to the file (the real file, not the symlink) + // Check that the file exists (the real file, not the symlink) try { this.mFso = CommandHelper.getFileInfo(this, path, true, null); if (this.mFso == null) { @@ -631,8 +629,36 @@ public class EditorActivity extends Activity implements TextWatcher { return; } - // Read the file in background - asyncRead(); + // Check that we have read access + try { + FileHelper.ensureReadAccess( + ConsoleBuilder.getConsole(this), + this.mFso, + null); + + // Read the file in background + asyncRead(); + + } catch (Exception ex) { + ExceptionUtil.translateException( + this, ex, false, true, new OnRelaunchCommandResult() { + @Override + public void onSuccess() { + // Read the file in background + asyncRead(); + } + + @Override + public void onFailed(Throwable cause) { + finish(); + } + + @Override + public void onCancelled() { + finish(); + } + }); + } } /** @@ -687,21 +713,6 @@ public class EditorActivity extends Activity implements TextWatcher { // Check if the read was successfully if (this.mReader.mCause != null) { - // Check if we can't read the file because we don't the require - // permissions. If we are in a ChRooted environment, resolve the - // error without doing anymore - if (this.mReader.mCause instanceof InsufficientPermissionsException) { - if (!ConsoleBuilder.isPrivileged() && - FileManagerApplication.getAccessMode(). - compareTo(AccessMode.SAFE) != 0) { - // We don't have a privileged console, we can't ask the user - // to gain privileges and relauch the command again - askGainAccessAndRead( - (RelaunchableException)this.mReader.mCause); - return Boolean.TRUE; - } - } - this.mCause = this.mReader.mCause; return Boolean.FALSE; } @@ -778,10 +789,40 @@ public class EditorActivity extends Activity implements TextWatcher { mReadTask.execute(this.mFso); } + private void checkAndWrite() { + // Check that we have write access + try { + FileHelper.ensureWriteAccess( + ConsoleBuilder.getConsole(this), + this.mFso, + null); + + // Write the file + syncWrite(); + + } catch (Exception ex) { + ExceptionUtil.translateException( + this, ex, false, true, new OnRelaunchCommandResult() { + @Override + public void onSuccess() { + // Write the file + syncWrite(); + } + + @Override + public void onFailed(Throwable cause) {/**NON BLOCK**/} + + @Override + public void onCancelled() {/**NON BLOCK**/} + }); + } + } + /** - * Method that reads the requested file. + * Method that write the file. + * @hide */ - private void writeFile() { + void syncWrite() { try { // Configure the writer AsyncWriter writer = new AsyncWriter(); @@ -846,53 +887,6 @@ public class EditorActivity extends Activity implements TextWatcher { } /** - * Method that asks the user for gain access and reexecute the read command - * - * @param cause The cause of the reexecution - * @hide - */ - void askGainAccessAndRead(final RelaunchableException cause) { - // We cannot use the ExceptionUtil class because the read command is asynchronous - // and doesn't have the common mechanism of capture exception. we do our self one. - - //Create a yes/no dialog and ask the user - runOnUiThread(new Runnable() { - @Override - public void run() { - AlertDialog alert = DialogHelper.createYesNoDialog( - EditorActivity.this, - R.string.confirm_operation, - cause.getQuestionResourceId(), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - // Change to privileged console - if (!ConsoleBuilder. - changeToPrivilegedConsole(EditorActivity.this)) { - - // Capture the exception - ExceptionUtil.translateException( - EditorActivity.this, - cause); - EditorActivity.this.mEditor.setEnabled(false); - return; - } - - //Read the file again - asyncRead(); - } else { - // Finish the application - EditorActivity.this.finish(); - } - } - }); - DialogHelper.delegateDialogShow(EditorActivity.this, alert); - } - }); - } - - /** * {@inheritDoc} */ @Override diff --git a/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java b/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java index cac8503e..2f491df7 100644 --- a/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java @@ -576,7 +576,7 @@ public class NavigationActivity extends Activity public void run() { //Create the default console (from the preferences) try { - Console console = ConsoleBuilder.createDefaultConsole(NavigationActivity.this); + Console console = ConsoleBuilder.getConsole(NavigationActivity.this); if (console == null) { throw new ConsoleAllocException("console == null"); //$NON-NLS-1$ } diff --git a/src/com/cyanogenmod/filemanager/activities/ShortcutActivity.java b/src/com/cyanogenmod/filemanager/activities/ShortcutActivity.java index 8c5a6674..d61b10b0 100644 --- a/src/com/cyanogenmod/filemanager/activities/ShortcutActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/ShortcutActivity.java @@ -200,7 +200,7 @@ public class ShortcutActivity extends Activity implements OnCancelListener, OnDi */ private boolean initializeConsole() { try { - ConsoleBuilder.createDefaultConsole(this); + ConsoleBuilder.getConsole(this); // There is a console allocated. Use it. return true; } catch (Throwable _throw) { diff --git a/src/com/cyanogenmod/filemanager/console/RelaunchableException.java b/src/com/cyanogenmod/filemanager/console/RelaunchableException.java index db5ece7b..9bb0e10a 100644 --- a/src/com/cyanogenmod/filemanager/console/RelaunchableException.java +++ b/src/com/cyanogenmod/filemanager/console/RelaunchableException.java @@ -41,7 +41,9 @@ public abstract class RelaunchableException extends Exception { public RelaunchableException(SyncResultExecutable executable) { super(); this.mExecutables = new ArrayList<SyncResultExecutable>(); - addExecutable(executable); + if (executable != null) { + addExecutable(executable); + } } /** @@ -53,7 +55,9 @@ public abstract class RelaunchableException extends Exception { public RelaunchableException(String detailMessage, SyncResultExecutable executable) { super(detailMessage); this.mExecutables = new ArrayList<SyncResultExecutable>(); - addExecutable(executable); + if (executable != null) { + addExecutable(executable); + } } /** @@ -67,7 +71,9 @@ public abstract class RelaunchableException extends Exception { String detailMessage, Throwable throwable, SyncResultExecutable executable) { super(detailMessage, throwable); this.mExecutables = new ArrayList<SyncResultExecutable>(); - addExecutable(executable); + if (executable != null) { + addExecutable(executable); + } } /** diff --git a/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java b/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java index 2edb42a9..daf30525 100644 --- a/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java +++ b/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java @@ -17,6 +17,7 @@ package com.cyanogenmod.filemanager.console.java; import android.content.Context; +import android.os.Process; import android.util.Log; import com.cyanogenmod.filemanager.commands.Executable; @@ -32,7 +33,13 @@ import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; import com.cyanogenmod.filemanager.console.OperationTimeoutException; import com.cyanogenmod.filemanager.console.ReadOnlyFilesystemException; +import com.cyanogenmod.filemanager.model.AID; +import com.cyanogenmod.filemanager.model.Group; import com.cyanogenmod.filemanager.model.Identity; +import com.cyanogenmod.filemanager.model.User; +import com.cyanogenmod.filemanager.util.AIDHelper; + +import java.util.ArrayList; /** * An implementation of a {@link Console} based on a java implementation.<br/> @@ -110,7 +117,12 @@ public final class JavaConsole extends Console { */ @Override public Identity getIdentity() { - return null; + AID aid = AIDHelper.getAID(Process.myUid()); + if (aid == null) return null; + return new Identity( + new User(aid.getId(), aid.getName()), + new Group(aid.getId(), aid.getName()), + new ArrayList<Group>()); } /** diff --git a/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java index d35eddb2..811c85f3 100644 --- a/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java @@ -20,11 +20,15 @@ import android.content.Context; import android.content.DialogInterface; import android.widget.Toast; +import com.cyanogenmod.filemanager.console.ConsoleBuilder; import com.cyanogenmod.filemanager.listeners.OnRequestRefreshListener; import com.cyanogenmod.filemanager.model.FileSystemObject; import com.cyanogenmod.filemanager.ui.dialogs.ComputeChecksumDialog; import com.cyanogenmod.filemanager.ui.dialogs.FsoPropertiesDialog; import com.cyanogenmod.filemanager.util.DialogHelper; +import com.cyanogenmod.filemanager.util.ExceptionUtil; +import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult; +import com.cyanogenmod.filemanager.util.FileHelper; /** * A class with the convenience methods for resolve the display of info actions @@ -78,8 +82,33 @@ public final class InfoActionPolicy extends ActionsPolicy { */ public static void showComputeChecksumDialog( final Context ctx, final FileSystemObject fso) { - //Show a the filesystem info dialog - final ComputeChecksumDialog dialog = new ComputeChecksumDialog(ctx, fso); - dialog.show(); + // Check that we have read access + try { + FileHelper.ensureReadAccess( + ConsoleBuilder.getConsole(ctx), + fso, + null); + + //Show a the filesystem info dialog + final ComputeChecksumDialog dialog = new ComputeChecksumDialog(ctx, fso); + dialog.show(); + + } catch (Exception ex) { + ExceptionUtil.translateException( + ctx, ex, false, true, new OnRelaunchCommandResult() { + @Override + public void onSuccess() { + //Show a the filesystem info dialog + final ComputeChecksumDialog dialog = new ComputeChecksumDialog(ctx, fso); + dialog.show(); + } + + @Override + public void onFailed(Throwable cause) {/**NON BLOCK**/} + + @Override + public void onCancelled() {/**NON BLOCK**/} + }); + } } -}
\ No newline at end of file +} diff --git a/src/com/cyanogenmod/filemanager/util/FileHelper.java b/src/com/cyanogenmod/filemanager/util/FileHelper.java index eff18ced..d1515047 100644 --- a/src/com/cyanogenmod/filemanager/util/FileHelper.java +++ b/src/com/cyanogenmod/filemanager/util/FileHelper.java @@ -23,8 +23,11 @@ import android.util.Log; import com.cyanogenmod.filemanager.FileManagerApplication; import com.cyanogenmod.filemanager.R; +import com.cyanogenmod.filemanager.commands.SyncResultExecutable; import com.cyanogenmod.filemanager.commands.shell.ResolveLinkCommand; +import com.cyanogenmod.filemanager.console.Console; import com.cyanogenmod.filemanager.console.ExecutionException; +import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; import com.cyanogenmod.filemanager.model.AID; import com.cyanogenmod.filemanager.model.BlockDevice; import com.cyanogenmod.filemanager.model.CharacterDevice; @@ -32,6 +35,7 @@ import com.cyanogenmod.filemanager.model.Directory; import com.cyanogenmod.filemanager.model.DomainSocket; import com.cyanogenmod.filemanager.model.FileSystemObject; import com.cyanogenmod.filemanager.model.Group; +import com.cyanogenmod.filemanager.model.Identity; import com.cyanogenmod.filemanager.model.NamedPipe; import com.cyanogenmod.filemanager.model.ParentDirectory; import com.cyanogenmod.filemanager.model.Permissions; @@ -184,29 +188,6 @@ public final class FileHelper { } /** - * Method that returns if an file system object requires elevated privileges. - * This occurs when the user is "root" or when the user console doesn't have - * sufficient permissions over the file system object. - * - * @param fso File system object - * @return boolean If the file system object requires elevated privileges - */ - public static boolean isPrivileged(FileSystemObject fso) { - //Parent directory doesn't require privileges - if (fso instanceof ParentDirectory) { - return false; - } - - //Checks if user is the administrator user - if (fso.getUser().getName().compareTo(USER_ROOT) == 0) { - return true; - } - - //No privileged - return false; - } - - /** * Method that returns if the file system object if the root directory. * * @param fso The file system object to check @@ -1115,4 +1096,169 @@ public final class FileHelper { } return new File(file, ".nomedia").getAbsoluteFile(); //$NON-NLS-1$ } + + /** + * Method that ensures that the actual console has access to read the + * {@link FileSystemObject} passed. + * + * @param console The console + * @param fso The {@link FileSystemObject} to check + * @param executable The executable to associate to the {@link InsufficientPermissionsException} + * @throws InsufficientPermissionsException If the console doesn't have enough rights + */ + public static void ensureReadAccess( + Console console, FileSystemObject fso, SyncResultExecutable executable) + throws InsufficientPermissionsException { + try { + if (console.isPrivileged()) { + // Should have access + return; + } + Identity identity = console.getIdentity(); + if (identity == null) { + throw new InsufficientPermissionsException(executable); + } + Permissions permissions = fso.getPermissions(); + User user = fso.getUser(); + Group group = fso.getGroup(); + List<Group> groups = identity.getGroups(); + if ( permissions == null || user == null || group == null) { + throw new InsufficientPermissionsException(executable); + } + // Check others + if (permissions.getOthers().isRead() ){ + return; + } + // Check user + if (user.getId() == identity.getUser().getId() && permissions.getUser().isRead() ){ + return; + } + // Check group + if (group.getId() == identity.getGroup().getId() && permissions.getGroup().isRead() ){ + return; + } + // Check groups + int cc = groups.size(); + for (int i = 0; i < cc; i++) { + Group g = groups.get(i); + if (group.getId() == g.getId() && permissions.getGroup().isRead() ){ + return; + } + } + + } catch (Exception e) { + Log.e(TAG, "Failed to check fso read permission,", e); //$NON-NLS-1$ + } + throw new InsufficientPermissionsException(executable); + } + + /** + * Method that ensures that the actual console has access to write the + * {@link FileSystemObject} passed. + * + * @param console The console + * @param fso The {@link FileSystemObject} to check + * @param executable The executable to associate to the {@link InsufficientPermissionsException} + * @throws InsufficientPermissionsException If the console doesn't have enough rights + */ + public static void ensureWriteAccess( + Console console, FileSystemObject fso, SyncResultExecutable executable) + throws InsufficientPermissionsException { + try { + if (console.isPrivileged()) { + // Should have access + return; + } + Identity identity = console.getIdentity(); + if (identity == null) { + throw new InsufficientPermissionsException(executable); + } + Permissions permissions = fso.getPermissions(); + User user = fso.getUser(); + Group group = fso.getGroup(); + List<Group> groups = identity.getGroups(); + if ( permissions == null || user == null || group == null) { + throw new InsufficientPermissionsException(executable); + } + // Check others + if (permissions.getOthers().isWrite() ){ + return; + } + // Check user + if (user.getId() == identity.getUser().getId() && permissions.getUser().isWrite() ){ + return; + } + // Check group + if (group.getId() == identity.getGroup().getId() && permissions.getGroup().isWrite() ){ + return; + } + // Check groups + int cc = groups.size(); + for (int i = 0; i < cc; i++) { + Group g = groups.get(i); + if (group.getId() == g.getId() && permissions.getGroup().isWrite() ){ + return; + } + } + + } catch (Exception e) { + Log.e(TAG, "Failed to check fso write permission,", e); //$NON-NLS-1$ + } + throw new InsufficientPermissionsException(executable); + } + + /** + * Method that ensures that the actual console has access to execute the + * {@link FileSystemObject} passed. + * + * @param console The console + * @param fso The {@link FileSystemObject} to check + * @param executable The executable to associate to the {@link InsufficientPermissionsException} + * @throws InsufficientPermissionsException If the console doesn't have enough rights + */ + public static void ensureExecuteAccess( + Console console, FileSystemObject fso, SyncResultExecutable executable) + throws InsufficientPermissionsException { + try { + if (console.isPrivileged()) { + // Should have access + return; + } + Identity identity = console.getIdentity(); + if (identity == null) { + throw new InsufficientPermissionsException(executable); + } + Permissions permissions = fso.getPermissions(); + User user = fso.getUser(); + Group group = fso.getGroup(); + List<Group> groups = identity.getGroups(); + if ( permissions == null || user == null || group == null) { + throw new InsufficientPermissionsException(executable); + } + // Check others + if (permissions.getOthers().isExecute() ){ + return; + } + // Check user + if (user.getId() == identity.getUser().getId() && permissions.getUser().isExecute() ){ + return; + } + // Check group + if (group.getId() == identity.getGroup().getId() && permissions.getGroup().isExecute() ){ + return; + } + // Check groups + int cc = groups.size(); + for (int i = 0; i < cc; i++) { + Group g = groups.get(i); + if (group.getId() == g.getId() && permissions.getGroup().isExecute() ){ + return; + } + } + + } catch (Exception e) { + Log.e(TAG, "Failed to check fso execute permission,", e); //$NON-NLS-1$ + } + throw new InsufficientPermissionsException(executable); + } } |