CookieSyncManager.java revision 87af7314d4319a0ccaaf466a25e3fe4f416cc953
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    private CookieSyncManager(Context context) {
69        super(context, "CookieSyncManager");
70    }
71
72    /**
73     * Singleton access to a {@link CookieSyncManager}. An
74     * IllegalStateException will be thrown if
75     * {@link CookieSyncManager#createInstance(Context)} is not called before.
76     *
77     * @return CookieSyncManager
78     */
79    public static synchronized CookieSyncManager getInstance() {
80        checkInstanceIsCreated();
81        return sRef;
82    }
83
84    /**
85     * Create a singleton CookieSyncManager within a context
86     * @param context
87     * @return CookieSyncManager
88     */
89    public static synchronized CookieSyncManager createInstance(
90            Context context) {
91        if (context == null) {
92            throw new IllegalArgumentException("Invalid context argument");
93        }
94
95        JniUtil.setContext(context);
96        Context appContext = context.getApplicationContext();
97        if (sRef == null) {
98            sRef = new CookieSyncManager(appContext);
99        }
100        return sRef;
101    }
102
103    /**
104     * Package level api, called from CookieManager. Get all the cookies which
105     * matches a given base domain.
106     * @param domain
107     * @return A list of Cookie
108     */
109    ArrayList<Cookie> getCookiesForDomain(String domain) {
110        // null mDataBase implies that the host application doesn't support
111        // persistent cookie. No sync needed.
112        if (mDataBase == null) {
113            return new ArrayList<Cookie>();
114        }
115
116        return mDataBase.getCookiesForDomain(domain);
117    }
118
119    /**
120     * Package level api, called from CookieManager Clear all cookies in the
121     * database
122     */
123    void clearAllCookies() {
124        // null mDataBase implies that the host application doesn't support
125        // persistent cookie.
126        if (mDataBase == null) {
127            return;
128        }
129
130        mDataBase.clearCookies();
131    }
132
133    /**
134     * Returns true if there are any saved cookies.
135     */
136    boolean hasCookies() {
137        // null mDataBase implies that the host application doesn't support
138        // persistent cookie.
139        if (mDataBase == null) {
140            return false;
141        }
142
143        return mDataBase.hasCookies();
144    }
145
146    /**
147     * Package level api, called from CookieManager Clear all session cookies in
148     * the database
149     */
150    void clearSessionCookies() {
151        // null mDataBase implies that the host application doesn't support
152        // persistent cookie.
153        if (mDataBase == null) {
154            return;
155        }
156
157        mDataBase.clearSessionCookies();
158    }
159
160    /**
161     * Package level api, called from CookieManager Clear all expired cookies in
162     * the database
163     */
164    void clearExpiredCookies(long now) {
165        // null mDataBase implies that the host application doesn't support
166        // persistent cookie.
167        if (mDataBase == null) {
168            return;
169        }
170
171        mDataBase.clearExpiredCookies(now);
172    }
173
174    protected void syncFromRamToFlash() {
175        if (DebugFlags.COOKIE_SYNC_MANAGER) {
176            Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
177        }
178
179        CookieManager manager = CookieManager.getInstance();
180
181        if (!manager.acceptCookie()) {
182            return;
183        }
184
185        if (JniUtil.useChromiumHttpStack()) {
186            manager.flushCookieStore();
187        } else {
188            ArrayList<Cookie> cookieList = manager.getUpdatedCookiesSince(mLastUpdate);
189            mLastUpdate = System.currentTimeMillis();
190            syncFromRamToFlash(cookieList);
191
192            ArrayList<Cookie> lruList = manager.deleteLRUDomain();
193            syncFromRamToFlash(lruList);
194        }
195
196        if (DebugFlags.COOKIE_SYNC_MANAGER) {
197            Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE");
198        }
199    }
200
201    private void syncFromRamToFlash(ArrayList<Cookie> list) {
202        Iterator<Cookie> iter = list.iterator();
203        while (iter.hasNext()) {
204            Cookie cookie = iter.next();
205            if (cookie.mode != Cookie.MODE_NORMAL) {
206                if (cookie.mode != Cookie.MODE_NEW) {
207                    mDataBase.deleteCookies(cookie.domain, cookie.path,
208                            cookie.name);
209                }
210                if (cookie.mode != Cookie.MODE_DELETED) {
211                    mDataBase.addCookie(cookie);
212                    CookieManager.getInstance().syncedACookie(cookie);
213                } else {
214                    CookieManager.getInstance().deleteACookie(cookie);
215                }
216            }
217        }
218    }
219
220    private static void checkInstanceIsCreated() {
221        if (sRef == null) {
222            throw new IllegalStateException(
223                    "CookieSyncManager::createInstance() needs to be called "
224                            + "before CookieSyncManager::getInstance()");
225        }
226    }
227}
228