/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.android.internal.os;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
public class RegionalizationEnvironment {
private final static String TAG = "RegionalizationEnvironment";
private final static boolean SUPPORTED = SystemProperties.getBoolean(
"ro.regionalization.support", false);
private final static boolean DEBUG = true;
private static IRegionalizationService mRegionalizationService = null;
private final static String SPEC_FILE_PATH = "/persist/speccfg/spec";
private static ArrayList<Package> mPackages = new ArrayList<Package>();
private static ArrayList<String> mExcludedApps = new ArrayList<String>();
private static boolean isLoaded = false;
private static void init() {
IBinder iBinder = ServiceManager.getService("regionalization");
mRegionalizationService = IRegionalizationService.Stub.asInterface(iBinder);
if (mRegionalizationService != null) {
loadSwitchedPackages();
loadExcludedApplist();
isLoaded = true;
}
}
/**
* {@hide}
*/
public static boolean isSupported() {
if (SUPPORTED && !isLoaded) {
init();
}
return SUPPORTED;
}
/**
* {@hide}
*/
public static int getPackagesCount() {
return mPackages.size();
}
/**
* {@hide}
*/
public static List<String> getAllPackageNames() {
ArrayList<String> packages = new ArrayList<String>();
for (Package p : mPackages) {
packages.add(p.getName());
}
return packages;
}
/**
* {@hide}
*/
public static List<File> getAllPackageDirectories() {
ArrayList<File> directories = new ArrayList<File>();
for (Package p : mPackages) {
if (DEBUG)
Log.v(TAG, "Package Directoriy(" + p.getPriority() + "):" + p.getDirectory());
directories.add(p.getDirectory());
}
return directories;
}
/**
* {@hide}
*/
public static boolean isExcludedApp(String appName) {
if (getPackagesCount() == 0) {
return false;
}
if (!appName.endsWith(".apk")) {
return mExcludedApps.contains(appName + ".apk");
} else {
return mExcludedApps.contains(appName);
}
}
/**
* {@hide}
*/
public static IRegionalizationService getRegionalizationService() {
return mRegionalizationService;
}
/**
* {@hide}
*/
public static String getStoragePos() {
for (Package pack: mPackages) {
String pos = pack.getStoragePos();
if (!TextUtils.isEmpty(pos))
return pos;
}
try {
mPackages.clear();
throw new IOException("Read wrong package for Carrier!");
} catch (IOException e) {
Log.e(TAG, "Get storage pos error, caused by: " + e.getMessage());
}
return "";
}
private static void loadSwitchedPackages() {
if (DEBUG)
Log.d(TAG, "load packages for Carrier!");
try {
ArrayList<String> contents = null;
try {
contents = (ArrayList<String>)
mRegionalizationService.readFile(SPEC_FILE_PATH, null);
} catch (RemoteException e) {
e.printStackTrace();
}
if (contents != null && contents.size() > 0) {
// Get storage pos of carrier pack
if (!contents.get(0).startsWith("packStorage=")) {
throw new IOException("Can't read storage pos for Carrier package!");
}
String storagePos = contents.get(0).substring("packStorage=".length());
if (TextUtils.isEmpty(storagePos)) {
throw new IOException("Storage pos for Carrier package is wrong!");
}
// Get carrier pack count
String packNumRegularExpresstion = "^packCount=[0-9]$";
if (!contents.get(1).matches(packNumRegularExpresstion)) {
throw new IOException("Can't read package count of Carrier!");
}
int packNum = Integer.parseInt(contents.get(1)
.substring("packCount=".length()));
if (packNum <= 0 || contents.size() <= packNum) {
throw new IOException("Package count of Carrier is wrong!");
}
for (int i = 2; i < packNum + 2; i++) {
String packRegularExpresstion = "^strSpec[0-9]=\\w+$";
if (contents.get(i).matches(packRegularExpresstion)) {
String packName = contents.get(i).substring("strSpec".length() + 2);
if (!TextUtils.isEmpty(packName)) {
boolean exists = false;
try {
exists = mRegionalizationService.checkFileExists(
storagePos + "/" + packName);
} catch (RemoteException e) {
e.printStackTrace();
}
if (exists) {
mPackages.add(new Package(packName, i, storagePos));
} else {
mPackages.clear();
throw new IOException("Read wrong packages for Carrier!");
}
}
} else {
mPackages.clear();
throw new IOException("Read wrong packages for Carrier!");
}
}
}
} catch (IOException e) {
Log.e(TAG, "Load package for carrier error, caused by: " + e.getMessage());
}
}
private static void loadExcludedApplist() {
if (DEBUG)
Log.d(TAG, "loadExcludedApps!");
if (getPackagesCount() == 0) return;
for (Package pack : mPackages) {
Log.d(TAG, "load excluded apps for " + pack.getDirectory());
String excListFilePath = pack.getExcludedListFilePath();
ArrayList<String> contents = null;
try {
contents = (ArrayList<String>)
mRegionalizationService.readFile(excListFilePath, null);
} catch (RemoteException e) {
e.printStackTrace();
}
if (contents != null && contents.size() > 0) {
for (String content : contents) {
if (!TextUtils.isEmpty(content)) {
int pos = content.lastIndexOf("/");
if (pos != -1) {
String apkName = content.substring(pos + 1);
if (!TextUtils.isEmpty(apkName) && !mExcludedApps.contains(apkName)) {
mExcludedApps.add(apkName);
}
}
}
}
}
}
}
private static class Package {
private final String mName;
private final int mPriority;
private final String mStorage;
public Package(String name, int priority, String storage) {
mName = name;
mPriority = priority;
mStorage = storage;
}
public String getName() {
return mName;
}
public int getPriority() {
return mPriority;
}
public String getStoragePos() {
return mStorage;
}
public File getDirectory() {
return new File(mStorage, mName);
}
public String getExcludedListFilePath() {
return getDirectory().getAbsolutePath() + "/exclude.list";
}
}
}