CookieSyncManager.java revision 82d98161362750ed280675b704a5ae467091cfba
1/* 2 * Copyright (C) 2007 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 17package android.webkit; 18 19import android.content.Context; 20import android.util.Log; 21import android.webkit.CookieManager.Cookie; 22 23import java.util.ArrayList; 24import java.util.Iterator; 25 26/** 27 * The CookieSyncManager is used to synchronize the browser cookie store 28 * between RAM and permanent storage. To get the best performance, browser cookies are 29 * saved in RAM. A separate thread saves the cookies between, driven by a timer. 30 * <p> 31 * 32 * To use the CookieSyncManager, the host application has to call the following 33 * when the application starts: 34 * <p> 35 * 36 * <pre class="prettyprint">CookieSyncManager.createInstance(context)</pre><p> 37 * 38 * To set up for sync, the host application has to call<p> 39 * <pre class="prettyprint">CookieSyncManager.getInstance().startSync()</pre><p> 40 * 41 * in Activity.onResume(), and call 42 * <p> 43 * 44 * <pre class="prettyprint"> 45 * CookieSyncManager.getInstance().stopSync() 46 * </pre><p> 47 * 48 * in Activity.onPause().<p> 49 * 50 * To get instant sync instead of waiting for the timer to trigger, the host can 51 * call 52 * <p> 53 * <pre class="prettyprint">CookieSyncManager.getInstance().sync()</pre><p> 54 * 55 * The sync interval is 5 minutes, so you will want to force syncs 56 * manually anyway, for instance in {@link 57 * WebViewClient#onPageFinished}. Note that even sync() happens 58 * asynchronously, so don't do it just as your activity is shutting 59 * down. 60 */ 61public final class CookieSyncManager extends WebSyncManager { 62 63 private static CookieSyncManager sRef; 64 65 // time when last update happened 66 private long mLastUpdate; 67 68 // Used by the Chromium HTTP stack. Everything else in this class is used only by the Android 69 // Java HTTP stack. 70 private static String sDatabaseDirectory; 71 private static String sCacheDirectory; 72 73 private CookieSyncManager(Context context) { 74 super(context, "CookieSyncManager"); 75 } 76 77 /** 78 * Singleton access to a {@link CookieSyncManager}. An 79 * IllegalStateException will be thrown if 80 * {@link CookieSyncManager#createInstance(Context)} is not called before. 81 * 82 * @return CookieSyncManager 83 */ 84 public static synchronized CookieSyncManager getInstance() { 85 checkInstanceIsCreated(); 86 return sRef; 87 } 88 89 /** 90 * Create a singleton CookieSyncManager within a context 91 * @param context 92 * @return CookieSyncManager 93 */ 94 public static synchronized CookieSyncManager createInstance( 95 Context context) { 96 Context appContext = context.getApplicationContext(); 97 if (sRef == null) { 98 sRef = new CookieSyncManager(appContext); 99 sDatabaseDirectory = appContext.getDatabasePath("dummy").getParent(); 100 sCacheDirectory = appContext.getCacheDir().getAbsolutePath(); 101 } 102 return sRef; 103 } 104 105 /** 106 * Package level api, called from CookieManager. Get all the cookies which 107 * matches a given base domain. 108 * @param domain 109 * @return A list of Cookie 110 */ 111 ArrayList<Cookie> getCookiesForDomain(String domain) { 112 // null mDataBase implies that the host application doesn't support 113 // persistent cookie. No sync needed. 114 if (mDataBase == null) { 115 return new ArrayList<Cookie>(); 116 } 117 118 return mDataBase.getCookiesForDomain(domain); 119 } 120 121 /** 122 * Package level api, called from CookieManager Clear all cookies in the 123 * database 124 */ 125 void clearAllCookies() { 126 // null mDataBase implies that the host application doesn't support 127 // persistent cookie. 128 if (mDataBase == null) { 129 return; 130 } 131 132 mDataBase.clearCookies(); 133 } 134 135 /** 136 * Returns true if there are any saved cookies. 137 */ 138 boolean hasCookies() { 139 // null mDataBase implies that the host application doesn't support 140 // persistent cookie. 141 if (mDataBase == null) { 142 return false; 143 } 144 145 return mDataBase.hasCookies(); 146 } 147 148 /** 149 * Package level api, called from CookieManager Clear all session cookies in 150 * the database 151 */ 152 void clearSessionCookies() { 153 // null mDataBase implies that the host application doesn't support 154 // persistent cookie. 155 if (mDataBase == null) { 156 return; 157 } 158 159 mDataBase.clearSessionCookies(); 160 } 161 162 /** 163 * Package level api, called from CookieManager Clear all expired cookies in 164 * the database 165 */ 166 void clearExpiredCookies(long now) { 167 // null mDataBase implies that the host application doesn't support 168 // persistent cookie. 169 if (mDataBase == null) { 170 return; 171 } 172 173 mDataBase.clearExpiredCookies(now); 174 } 175 176 protected void syncFromRamToFlash() { 177 if (DebugFlags.COOKIE_SYNC_MANAGER) { 178 Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS"); 179 } 180 181 if (!CookieManager.getInstance().acceptCookie()) { 182 return; 183 } 184 185 ArrayList<Cookie> cookieList = CookieManager.getInstance() 186 .getUpdatedCookiesSince(mLastUpdate); 187 mLastUpdate = System.currentTimeMillis(); 188 syncFromRamToFlash(cookieList); 189 190 ArrayList<Cookie> lruList = 191 CookieManager.getInstance().deleteLRUDomain(); 192 syncFromRamToFlash(lruList); 193 194 if (DebugFlags.COOKIE_SYNC_MANAGER) { 195 Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE"); 196 } 197 } 198 199 private void syncFromRamToFlash(ArrayList<Cookie> list) { 200 Iterator<Cookie> iter = list.iterator(); 201 while (iter.hasNext()) { 202 Cookie cookie = iter.next(); 203 if (cookie.mode != Cookie.MODE_NORMAL) { 204 if (cookie.mode != Cookie.MODE_NEW) { 205 mDataBase.deleteCookies(cookie.domain, cookie.path, 206 cookie.name); 207 } 208 if (cookie.mode != Cookie.MODE_DELETED) { 209 mDataBase.addCookie(cookie); 210 CookieManager.getInstance().syncedACookie(cookie); 211 } else { 212 CookieManager.getInstance().deleteACookie(cookie); 213 } 214 } 215 } 216 } 217 218 private static void checkInstanceIsCreated() { 219 if (sRef == null) { 220 throw new IllegalStateException( 221 "CookieSyncManager::createInstance() needs to be called " 222 + "before CookieSyncManager::getInstance()"); 223 } 224 } 225 226 /** 227 * Called by JNI. Gets the application's database directory, excluding the trailing slash. 228 * @return String The application's database directory 229 */ 230 private static synchronized String getDatabaseDirectory() { 231 checkInstanceIsCreated(); 232 return sDatabaseDirectory; 233 } 234 235 /** 236 * Called by JNI. Gets the application's cache directory, excluding the trailing slash. 237 * @return String The application's cache directory 238 */ 239 private static synchronized String getCacheDirectory() { 240 checkInstanceIsCreated(); 241 return sCacheDirectory; 242 } 243} 244