Home | History | Annotate | Download | only in sip
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.services.telephony.sip;
     18 
     19 import com.android.internal.os.AtomicFile;
     20 
     21 import android.content.Context;
     22 import android.net.sip.SipProfile;
     23 import android.text.TextUtils;
     24 import android.util.EventLog;
     25 import android.util.Log;
     26 
     27 import java.io.File;
     28 import java.io.FileOutputStream;
     29 import java.io.IOException;
     30 import java.io.ObjectInputStream;
     31 import java.io.ObjectOutputStream;
     32 import java.util.ArrayList;
     33 import java.util.Collections;
     34 import java.util.List;
     35 
     36 /**
     37  * Utility class that helps perform operations on the SipProfile database.
     38  */
     39 class SipProfileDb {
     40     private static final String PREFIX = "[SipProfileDb] ";
     41     private static final boolean VERBOSE = false; /* STOP SHIP if true */
     42 
     43     private static final String PROFILES_DIR = "/profiles/";
     44     private static final String PROFILE_OBJ_FILE = ".pobj";
     45 
     46     private static final String SCHEME_PREFIX = "sip:";
     47 
     48     private Context mContext;
     49     private String mProfilesDirectory;
     50     private SipPreferences mSipPreferences;
     51     private int mProfilesCount = -1;
     52 
     53     public SipProfileDb(Context context) {
     54         // Sip Profile Db should always reference CE storage.
     55         mContext = context.createCredentialProtectedStorageContext();
     56         setupDatabase();
     57     }
     58 
     59     // Only should be used during migration from M->N to move database
     60     public void accessDEStorageForMigration() {
     61         mContext = mContext.createDeviceProtectedStorageContext();
     62         setupDatabase();
     63     }
     64 
     65     private void setupDatabase() {
     66         mProfilesDirectory = mContext.getFilesDir().getAbsolutePath() + PROFILES_DIR;
     67         mSipPreferences = new SipPreferences(mContext);
     68     }
     69 
     70     public void deleteProfile(SipProfile p) throws IOException {
     71         synchronized(SipProfileDb.class) {
     72             File profileFile = new File(mProfilesDirectory, p.getProfileName());
     73             if (!isChild(new File(mProfilesDirectory), profileFile)) {
     74                 throw new IOException("Invalid Profile Credentials!");
     75             }
     76             deleteProfile(profileFile);
     77             if (mProfilesCount < 0) retrieveSipProfileListInternal();
     78         }
     79     }
     80 
     81     private void deleteProfile(File file) {
     82         if (file.isDirectory()) {
     83             for (File child : file.listFiles()) deleteProfile(child);
     84         }
     85         file.delete();
     86     }
     87 
     88     public void cleanupUponMigration() {
     89         // Remove empty .../profiles/ directory
     90         File dbDir = new File(mProfilesDirectory);
     91         if(dbDir.isDirectory()) {
     92             dbDir.delete();
     93         }
     94         // Remove SharedPreferences file as well
     95         mSipPreferences.clearSharedPreferences();
     96     }
     97 
     98     public void saveProfile(SipProfile p) throws IOException {
     99         synchronized(SipProfileDb.class) {
    100             if (mProfilesCount < 0) retrieveSipProfileListInternal();
    101             File f = new File(mProfilesDirectory, p.getProfileName());
    102             if (!isChild(new File(mProfilesDirectory), f)) {
    103                 throw new IOException("Invalid Profile Credentials!");
    104             }
    105             if (!f.exists()) f.mkdirs();
    106             AtomicFile atomicFile = new AtomicFile(new File(f, PROFILE_OBJ_FILE));
    107             FileOutputStream fos = null;
    108             ObjectOutputStream oos = null;
    109             try {
    110                 fos = atomicFile.startWrite();
    111                 oos = new ObjectOutputStream(fos);
    112                 oos.writeObject(p);
    113                 oos.flush();
    114                 atomicFile.finishWrite(fos);
    115             } catch (IOException e) {
    116                 atomicFile.failWrite(fos);
    117                 throw e;
    118             } finally {
    119                 if (oos != null) oos.close();
    120             }
    121         }
    122     }
    123 
    124     public List<SipProfile> retrieveSipProfileList() {
    125         synchronized(SipProfileDb.class) {
    126             return retrieveSipProfileListInternal();
    127         }
    128     }
    129 
    130     private List<SipProfile> retrieveSipProfileListInternal() {
    131         List<SipProfile> sipProfileList = Collections.synchronizedList(
    132                 new ArrayList<SipProfile>());
    133 
    134         File root = new File(mProfilesDirectory);
    135         String[] dirs = root.list();
    136         if (dirs == null) return sipProfileList;
    137         for (String dir : dirs) {
    138             SipProfile p = retrieveSipProfileFromName(dir);
    139             if (p == null) continue;
    140             sipProfileList.add(p);
    141         }
    142         mProfilesCount = sipProfileList.size();
    143         return sipProfileList;
    144     }
    145 
    146     public SipProfile retrieveSipProfileFromName(String name) {
    147         if (TextUtils.isEmpty(name)) {
    148             return null;
    149         }
    150 
    151         File root = new File(mProfilesDirectory);
    152         File f = new File(new File(root, name), PROFILE_OBJ_FILE);
    153         if (f.exists()) {
    154             try {
    155                 SipProfile p = deserialize(f);
    156                 if (p != null && name.equals(p.getProfileName())) {
    157                     return p;
    158                 }
    159             } catch (IOException e) {
    160                 log("retrieveSipProfileListInternal, exception: " + e);
    161             }
    162         }
    163         return null;
    164     }
    165 
    166     private SipProfile deserialize(File profileObjectFile) throws IOException {
    167         AtomicFile atomicFile = new AtomicFile(profileObjectFile);
    168         ObjectInputStream ois = null;
    169         try {
    170             ois = new ObjectInputStream(atomicFile.openRead());
    171             SipProfile p = (SipProfile) ois.readObject();
    172             return p;
    173         } catch (ClassNotFoundException e) {
    174             log("deserialize, exception: " + e);
    175         } finally {
    176             if (ois!= null) ois.close();
    177         }
    178         return null;
    179     }
    180 
    181     private static void log(String msg) {
    182         Log.d(SipUtil.LOG_TAG, PREFIX + msg);
    183     }
    184 
    185     /**
    186      * Verifies that the file is a direct child of the base directory.
    187      */
    188     private boolean isChild(File base, File file) {
    189         if (base == null || file == null) {
    190             return false;
    191         }
    192         if (!base.equals(file.getAbsoluteFile().getParentFile())) {
    193             Log.w(SipUtil.LOG_TAG, "isChild, file is not a child of the base dir.");
    194             EventLog.writeEvent(0x534e4554, "31530456", -1, "");
    195             return false;
    196         }
    197         return true;
    198     }
    199 }
    200