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