/*
* Copyright (C) 2012 The CyanogenMod Project
*
* 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 com.cyanogenmod.filemanager.console;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.cyanogenmod.filemanager.FileManagerApplication;
import com.cyanogenmod.filemanager.R;
import com.cyanogenmod.filemanager.commands.shell.InvalidCommandDefinitionException;
import com.cyanogenmod.filemanager.console.java.JavaConsole;
import com.cyanogenmod.filemanager.console.shell.NonPriviledgeConsole;
import com.cyanogenmod.filemanager.console.shell.PrivilegedConsole;
import com.cyanogenmod.filemanager.preferences.AccessMode;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.Preferences;
import com.cyanogenmod.filemanager.util.DialogHelper;
import com.cyanogenmod.filemanager.util.FileHelper;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Class responsible for creating consoles.
*/
public final class ConsoleBuilder {
private static final String TAG = "ConsoleBuilder"; //$NON-NLS-1$
private static final Object SYNC = new Object();
private static ConsoleHolder sHolder;
private static final int ROOT_UID = 0;
/**
* Constructor of <code>ConsoleBuilder</code>.
*/
private ConsoleBuilder() {
super();
}
/**
* Method that returns a console, and creates a new console
* if no console is allocated. The console is create if not exists.
*
* @param context The current context
* @return Console An allocated console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @throws InsufficientPermissionsException If the console created is not a privileged console
*/
public static Console getConsole(Context context)
throws FileNotFoundException, IOException, InvalidCommandDefinitionException,
ConsoleAllocException, InsufficientPermissionsException {
return getConsole(context, true);
}
/**
* Method that returns a console. If {@linkplain "createIfNotExists"} is specified
* a new console will be created
*
* @param context The current context
* @param createIfNotExists Indicates that the console should be create if not exists
* @return Console An allocated console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @throws InsufficientPermissionsException If the console created is not a privileged console
*/
public static Console getConsole(Context context, boolean createIfNotExists)
throws FileNotFoundException, IOException, InvalidCommandDefinitionException,
ConsoleAllocException, InsufficientPermissionsException {
//Check if has a console. Otherwise create a new console
if (sHolder == null || sHolder.getConsole() == null) {
if (!createIfNotExists) {
return null;
}
createDefaultConsole(context);
} else {
// Need to change the console? Is the appropriate console for the current mode?
if (FileManagerApplication.getAccessMode().
compareTo(AccessMode.ROOT) == 0 && !isPrivileged()) {
// Force to change the console
createDefaultConsole(context);
}
}
return sHolder.getConsole();
}
/**
* Method that changes the current console to a non-privileged console.
*
* @param context The current context
* @return boolean If the operation was successfully
*/
public static boolean changeToNonPrivilegedConsole(Context context) {
//Check the current console
if (sHolder != null && sHolder.getConsole() instanceof NonPriviledgeConsole) {
//The current console is non-privileged. Not needed
return true;
}
//Create the console
ConsoleHolder holder = null;
try {
//Create the console, destroy the current console, and marks as current
holder = new ConsoleHolder(
createNonPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY));
destroyConsole();
sHolder = holder;
return true;
} catch (Throwable e) {
if (holder != null) {
holder.dispose();
}
}
return false;
}
/**
* Method that changes the current console to a privileged console.
*
* @param context The current context
* @return boolean If the operation was successfully
*/
public static boolean changeToPrivilegedConsole(Context context) {
//Destroy and create the new console
if (sHolder != null && sHolder.getConsole() instanceof PrivilegedConsole) {
//The current console is privileged. Not needed
return true;
}
//Create the console
ConsoleHolder holder = null;
try {
//Create the console, destroy the current console, and marks as current
holder = new ConsoleHolder(
createAndCheckPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY));
destroyConsole();
sHolder = holder;
// Change also the background console to privileged
FileManagerApplication.changeBackgroundConsoleToPriviligedConsole();
return sHolder.getConsole() instanceof PrivilegedConsole;
} catch (Throwable e) {
destroyConsole();
if (holder != null) {
holder.dispose();
}
}
return false;
}
/**
* Method that returns a console, and creates a new console if no
* console is allocated or if the settings preferences has changed.
*
* @param context The current context
* @return Console An allocated console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @throws InsufficientPermissionsException If the console created is not a privileged console
*/
//IMP! This must be invoked from the main activity creation
public static Console createDefaultConsole(Context context)
throws FileNotFoundException, IOException, InvalidCommandDefinitionException,
ConsoleAllocException, InsufficientPermissionsException {
//Gets superuser mode settings
boolean superuserMode =
FileManagerApplication.getAccessMode().compareTo(AccessMode.ROOT) == 0;
boolean advancedMode =
FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) != 0;
if (superuserMode && !advancedMode) {
try {
Preferences.savePreference(
FileManagerSettings.SETTINGS_ACCESS_MODE, AccessMode.PROMPT, true);
} catch (Throwable ex) {
Log.w(TAG, "can't save console preference", ex); //$NON-NLS-1$
}
superuserMode = false;
}
return createDefaultConsole(context, superuserMode, advancedMode);
}
/**
* Method that returns a console, and creates a new console if no
* console is allocated or if the settings preferences has changed.
*
* @param context The current context
* @param superuserMode If create with a superuser mode console (root access mode)
* @param advancedMode If create with a advanced mode console (prompt or root access mode)
* @return Console An allocated console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @throws InsufficientPermissionsException If the console created is not a privileged console
*/
//IMP! This must be invoked from the main activity creation
public static Console createDefaultConsole(Context context,
boolean superuserMode, boolean advancedMode)
throws FileNotFoundException, IOException, InvalidCommandDefinitionException,
ConsoleAllocException, InsufficientPermissionsException {
synchronized (ConsoleBuilder.SYNC) {
//Check if console settings has changed
if (sHolder != null) {
if (
(sHolder.getConsole() instanceof NonPriviledgeConsole && superuserMode)
|| (sHolder.getConsole() instanceof PrivilegedConsole && !superuserMode)) {
//Deallocate actual console
sHolder.dispose();
sHolder = null;
}
}
//Is there a console allocated
if (sHolder == null) {
sHolder = (superuserMode)
? new ConsoleHolder(
createAndCheckPrivilegedConsole(
context, FileHelper.ROOT_DIRECTORY))
: new ConsoleHolder(
createNonPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY));
if (superuserMode) {
// Change also the background console to privileged
FileManagerApplication.changeBackgroundConsoleToPriviligedConsole();
}
}
return sHolder.getConsole();
}
}
/**
* Method that destroy the current console.
*/
public static void destroyConsole() {
try {
if (sHolder != null) {
sHolder.dispose();
}
} catch (Exception e) {
/**NON BLOCK**/
}
sHolder = null;
}
/**
* Method that creates a new non privileged console.
*
* @param context The current context
* @param initialDirectory The initial directory of the console
* @return Console The non privileged console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @see NonPriviledgeConsole
*/
public static Console createNonPrivilegedConsole(Context context, String initialDirectory)
throws FileNotFoundException, IOException,
InvalidCommandDefinitionException, ConsoleAllocException {
int bufferSize = context.getResources().getInteger(R.integer.buffer_size);
// Is rooted? Then create a shell console
if (FileManagerApplication.isDeviceRooted()) {
NonPriviledgeConsole console = new NonPriviledgeConsole(initialDirectory);
console.setBufferSize(bufferSize);
console.alloc();
return console;
}
// No rooted. Then create a java console
JavaConsole console = new JavaConsole(context, initialDirectory, bufferSize);
console.alloc();
return console;
}
/**
* Method that creates a new privileged console. If the allocation of the
* privileged console fails, the a non privileged console
*
* @param context The current context
* @param initialDirectory The initial directory of the console
* @return Console The privileged console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @throws InsufficientPermissionsException If the console created is not a privileged console
* @see PrivilegedConsole
*/
public static Console createPrivilegedConsole(Context context, String initialDirectory)
throws FileNotFoundException, IOException, InvalidCommandDefinitionException,
ConsoleAllocException, InsufficientPermissionsException {
PrivilegedConsole console = new PrivilegedConsole(initialDirectory);
console.setBufferSize(context.getResources().getInteger(R.integer.buffer_size));
console.alloc();
if (console.getIdentity().getUser().getId() != ROOT_UID) {
//The console is not a privileged console
try {
console.dealloc();
} catch (Throwable ex) {
/**NON BLOCK**/
}
throw new InsufficientPermissionsException(null);
}
return console;
}
/**
* Method that creates a new privileged console. If the allocation of the
* privileged console fails, the a non privileged console
*
* @param context The current context
* @param initialDirectory The initial directory of the console
* @return Console The privileged console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @throws InsufficientPermissionsException If the console created is not a privileged console
* @see PrivilegedConsole
*/
public static Console createAndCheckPrivilegedConsole(Context context, String initialDirectory)
throws FileNotFoundException, IOException, InvalidCommandDefinitionException,
ConsoleAllocException, InsufficientPermissionsException {
return createAndCheckPrivilegedConsole(context, initialDirectory, true);
}
/**
* Method that creates a new privileged console. If the allocation of the
* privileged console fails, the a non privileged console
*
* @param context The current context
* @param initialDirectory The initial directory of the console
* @param silent Indicates that no message have to be displayed
* @return Console The privileged console
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws ConsoleAllocException If the console can't be allocated
* @throws InsufficientPermissionsException If the console created is not a privileged console
* @see PrivilegedConsole
*/
public static Console createAndCheckPrivilegedConsole(
Context context, String initialDirectory, boolean silent)
throws FileNotFoundException, IOException, InvalidCommandDefinitionException,
ConsoleAllocException, InsufficientPermissionsException {
try {
// Create the privileged console
return createPrivilegedConsole(context, initialDirectory);
} catch (ConsoleAllocException caEx) {
//Show a message with the problem?
Log.w(TAG, context.getString(R.string.msgs_privileged_console_alloc_failed), caEx);
if (!silent) {
try {
DialogHelper.showToast(context,
R.string.msgs_privileged_console_alloc_failed, Toast.LENGTH_LONG);
} catch (Exception ex) {
Log.e(TAG, "can't show toast", ex); //$NON-NLS-1$
}
}
boolean advancedMode =
FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) != 0;
if (advancedMode) {
//Save settings
try {
Preferences.savePreference(
FileManagerSettings.SETTINGS_ACCESS_MODE, AccessMode.PROMPT, true);
} catch (Exception ex) {
Log.e(TAG,
String.format("Failed to save %s property", //$NON-NLS-1$
FileManagerSettings.SETTINGS_ACCESS_MODE.getId()), ex);
}
//Create the non-privileged console
return createNonPrivilegedConsole(context, initialDirectory);
}
// Rethrow the exception
throw caEx;
}
}
/**
* Method that returns if the current console is a privileged console
*
* @return boolean If the current console is a privileged console
*/
public static boolean isAlloc() {
if (sHolder != null && sHolder.getConsole() != null) {
return true;
}
return false;
}
/**
* Method that returns if the current console is a privileged console
*
* @return boolean If the current console is a privileged console
*/
public static boolean isPrivileged() {
if (sHolder != null && sHolder.getConsole() instanceof PrivilegedConsole) {
return true;
}
return false;
}
}